ASP.NET Core – CORS (Cross-Origin Resource Sharing)
参考
Docs – Enable Cross-Origin Requests (CORS) in ASP.NET Core
介绍
CORS (Cross-Origin Resource Sharing) 讲的是游览器对跨域服务端发起 HTTP request (Ajax),被游览器禁止读取。
Chrome DevTools 会显示下面这些 error.
早年的解决方法是用 JSONP (用 <script> 发请求,服务端配合返回 JavaScript 并且调用一个全局方法,方法名字是通过 request query parameters 得知的,最后把资料传入方法中)。
现今只需要加上一些 response header 就可以了。
怎样算跨域
1. Domain 不一样
abc.com 和 abc.net
2. Sub domain 不一样
abc.com 和 www.abc.com
3. Scheme 不一样
http 和 https
4. Port 不一样
localhost:4200 和 localhost:61547
基本用法: AddCors & UseCors
和其它 ASP.NET Core module 用法差不多. Service.AddCors, App.UseCors
AddCors (for service)
创建 default policy, by pass all origin (这个适合在开发阶段, 下面会讲 production 阶段应该限制多一点, 不可以 by pass all)
builder.Services.AddCors(options => { options.AddDefaultPolicy(policy => { policy.AllowAnyOrigin() .AllowAnyMethod() .AllowAnyHeader(); }); });
UseCors (for middleware)
app.UseHttpsRedirection(); app.UseCors(); app.UseAuthorization();
位置很重要哦. 如果 JS 会请求 static file 的话, 那还得放到 app.UseStaticFiles 之上.
Policy Configuration
allow header & method
policy.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader();
method 和 header 是 for Preflight request (OPTIONS) 用的. 通常 set any 是 ok 的.
如果 request 有自定义 header,那也需要设置 header。
要限制也是可以
policy.WithMethods("POST", "PUT");
最终会输出
allow origin
origin 最好不要 set any. 很危险. 指定给需要的 origin 就好了.
policy.WithOrigins("https://192.168.1.152:4202");
注意, origin 的结尾不可以有 slash.
allow credentials
如果 request 要携带 cookie 的话需要特别开启
policy.AllowCredentials();
有用 SignalR 的话, 也一定要开启, 参考: Security considerations in ASP.NET Core SignalR
另外 AllowAnyOrigin 和 AllowCredentials 不可以一起使用 (应该是担心安全隐患太大吧)
allow exposed headers
跨域默认只允许 client 访问一些 response header
policy.WithExposedHeaders(“specify-header-name”, "x-custom-header");
通过 WithExposedHeaders 可以配置. 指定某个名字, 或者 by pass all 就用关键字 "x-custom-header"
Policy 管理
上面的例子在管理上是比较简单的. 一个项目一个配置就 ok 了.
但如果遇到比较复杂的项目就需要多一点管理了. 比如多个 Policy. 有些 Controller 允许 CORS 有些不允许.
Multiple Policy
上面我们用的是 AddDefaultPolicy, 这里用的是 AddPolicy 配上 policy name. 可以一直 AddPolicy, 只要确保名字是 unique 就可以了.
builder.Services.AddCors(options => { options.AddPolicy( name: "MyFirstCorsPolicy", configurePolicy: policy => { policy.WithOrigins(new[] { "https://192.168.1.152:4202" }).AllowAnyHeader().AllowAnyMethod().AllowCredentials(); } ); });
[EnableCors] 和 [DisableCors]
可以指定某个 Controller 使用哪一个 CORS Policy, 也可以 disable 某一个 Action
UseCors
不管是 default policy 还是 policy with name, 一定要调用 app.UseCors
app.UseCors();
app.UseCors(), 没有声明 policy name, 表示所有 Controller 使用 default policy (如果有 config default policy 的话, 没有的话 Controller 就得用 attribute 来控制)
app.UseCors("MyFirstCorsPolicy");
with policy name 表示所有 Controller 使用 MyFirstCorsPolicy policy, attribute 可以 override 这个设置.
简而言之就是, 用 attribute 去控制 Controller 和 Action. 用 app.UseCors 做全局控制 (不想全局控制, 就不要 set default policy, 但记得, 无论如何 app.UseCors 依然是需要调用的)