Angular、.NET Web Api 验证(Authentication)与跨来源资源共享(Cors)

验证是任何 Web 服务都必须考虑的基础问题。关于 .NET 平台的验证与授权,按理说微软已经提供了相当充分的文档与示例代码。

.NET Identity 框架提供了现成的数据库结构以及一系列接口,可以实现用户注册、登录登出、口令生成、邮箱的确认、密码重置等基本功能,也可以与社交媒体账户集成实现用户注册与登陆。

需要注意的是,.NET MVC 与 .NET Core 所使用的接口代码和 .NET Web Api 有所不同,如果混合阅读文档与代码,可能会造成混淆与理解上的困扰。不同版本的文档对邮箱验证等功能的处理逻辑也有差别,不可简单合并使用。

后端若部署至 Azure 等云平台,口令的生成也可能会遇到在本地不会发生的问题,报错“ The data protection operation was unsuccessful. This may have been caused by not having the user profile loaded for the current thread’s user context, which may be the case when the thread is impersonating.”。例如,.NET MVC 版示例代码在用户登录并验证邮箱后生成口令时会试图调用 /Token 接口,触发错误。网上针对此问题有一些解决方案,却都不太有效。事实上,可暂时忽略对邮箱是否得到验证的检查,直接前台调用 /Token 接口,就能避免该错误。对邮箱的确认可以在之后实际执行处理时按需进行。

微软官方的示例代码都没有涉及 Cors(cross origin resource sharing) 问题,即使是 Angular 项目模板,由于前端默认与后端共存于同一个解决方案,也不存在这一问题。然而,如果前后端分离,前端 Angular 程序的域名很可能与后端不同。

微软针对 .NET Web Api 的 Cors 有一些文档,但很遗憾,如果有接口通过 bearer token 进行验证与授权,那些文档中的解决方案很可能会引发新的问题。

  • .NET Web Api 中对 允许跨源访问:介绍多种允许 Cross origin request 的方式

由于 Chrome 等一些浏览器在一定条件下出于安全原因为首先发送 OPTIONS method 的 HTTP 请求(如 headers 中指定 “Content-Type”: “application/x-www-form-urlencoded” 时),情况变得更加复杂。

如果 OPTIONS method 没有被允许,则会遇到 405 错误代码。不当的设置可能会在允许跨源访问资源时却阻碍了用户登录等验证 API。又或是无意中重复允许 Cors origin 设置,会提示 The ‘Access-Control-Allow-Origin’ header contains multiple values 错误而无法获得资源。

网络上简单明了且实际有效的解决方案并不好找,经过反复尝试与分析,要避免所有这类问题,采用全局设置恐怕是最简单的方法之一。

  • 不要像下面这样通过 Web.config 来设置 Cors

  • 不要像下面这样通过 ApiController 属性来设置 Cors

  • 不要在 WebApiConfig 等类中通过诸如 config.EnableCors(); 等代码方式设置 Cors
  • 安装 Microsoft.Owin.Cors 的 NuGet 包
  • 在 startup.cs 的 ConfigureAuth 方法开始时调用语句 app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
  • Angular 前端发送请求时, headers 中只需指定 “Content-Type”: “application/x-www-form-urlencoded” 一项即可
  • 如果使用 RestAngular 获取资源,只需按如下方式设置 Content-Type 与 Authorization 即可

至此,运行于 Azure App Service 的后端 .NET Web Api 将可以与非同源的 Angular 程序交互,实现本地用户账号的注册登陆等操作,可以通过 bearer token 实现资源请求过程中的验证与授权。