介绍
浏览器安全不允许不同域名的网页之间发送请求。这种限制叫做浏览器同源策略(the same-origin policy)。
实现跨域请求有以下方法:JSONP,Proxy,CORS,Nginx,Socket...
JSONP:
JSONP实现原理:利用script标签不受同源策略限制,在页面动态添加script,script标签的src属性设成api地址,并将回调函数名以get方式告诉后端,后端将数据以参数的形式返回
JSONP的优缺点:只能发get请求、不安全、老式浏览器支持性好
Proxy:
通过代理服务器转发请求,实现跨域
CORS
老版浏览器不支持、支持所有谓词请求,推荐使用
带策略的CORS 和中间件
CORS中间件处理跨域请求。下面的代码允许指定的源能对整个应用进行跨域请求
案例:
CORS中间件处理跨域请求。下面的代码允许指定的源能对整个应用进行跨域请求
这个代码会把CORS策略通过CORS中间件应用到这个应用的所有终端(endpoints);即把跨域作用到整个应用
指定域名可以跨域请求:
public void ConfigureServices(IServiceCollection services)
{
string[] origins = new string[] { "http://*.fan.com", "https://*.fan.com", "http://*.fan.net", "https://*.fan.net" };
services.AddCors(option => option.AddPolicy("cors", policy => policy
.AllowAnyHeader()//允许所有的请求头
//.WithHeaders(HeaderNames.ContentType, "x-custom-header");//要允许一个CORS请求中指定的请求头,可以使用 WithHeaders 来指定
.AllowAnyMethod()//允许所有Method
.SetIsOriginAllowedToAllowWildcardSubdomains()//使可以匹配一个配置的带通配符的域名
.WithOrigins(origins) //指定来源域名
.AllowCredentials() //允许浏览器在跨域请求中发送证书
));
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IHostApplicationLifetime applicationLifetime, ILogger<Startup> logger , ElasticSearch elasticSearch)
{
app.UseCors("cors");//注意:1.UseCors必须在UseMvc之前被调用;2. URL末尾不能加/ ;这个url指的是 builder.WithOrigins(url)中的url
}
不做限制,允许所有域名跨域请求:
services.AddCors(option => option.AddPolicy("cors", policy => policy
.AllowAnyHeader()
.AllowAnyMethod()
.SetIsOriginAllowed(_ => true) //不做任何限制
.AllowCredentials()
)
);
使用[EnableCors]属性设置允许跨域
[EnableCors]属性提供了另一种方式设置跨域。即可以只设置选择的终端,而不是所有的终端.
这里不同于上面的那种方式,上面的方式是应用的所有终端都会被设置允许跨域;
使用[EnableCors]来指定默认的策略,而[EnableCors("{Policy String}")] 指定了特定的策略;
[DisableCors]属性可以禁止CORS;
[EnableCors("AnotherPolicy")]
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "green widget", "red widget" };
}
CORS 策略(Policy)的选项:
- 设置允许的访问源
- 设置允许的HTTP methods
- 设置允许的请求头(request header)
- 设置暴露的响应头(response header)
- 跨不同源请求的证书(Credentials)
- 设置过期时间
SetIsOriginAllowedToAllowWildcardSubdomains:设置策略的 IsOriginAllowed 属性,使可以匹配一个配置的带通配符的域名
AllowAnyMethod:设置允许的HTTP methods
WithHeaders:要允许一个CORS请求中指定的请求头,可以使用 WithHeaders 来指定
AllowAnyHeader:允许所有的请求头
withCredentials:允许在跨域请求中发送证书
WithExposedHeaders:暴露指定的响应头
注意:如果 Access-Control-Allow-Credentials 头部出现了,则意味着 设置为所有的源 (setting origin to " * ")会失效。
.NET Framework中实现跨域
CROS:
/// <summary>
/// 支持WebAPI服务器端跨域
/// </summary>
public class ServerCrossDomainAttribute : ActionFilterAttribute
{
public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
{
HttpRequestHeaders requestHeaders = actionExecutedContext.Request.Headers;
if (requestHeaders.Contains("Origin"))
{
string originHeader = requestHeaders.GetValues("Origin").FirstOrDefault();
if (!string.IsNullOrEmpty(originHeader))
{
HttpResponseHeaders responseHeaders = actionExecutedContext.Response.Headers;
responseHeaders.Add("Access-Control-Allow-Origin", originHeader);
responseHeaders.Add("Access-Control-Allow-Credentials", "true");
actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept, Authorization");
}
}
}
}
JSONP:
/// <summary>
/// 支持WebAPI客户端跨域,jsonp
/// </summary>
public class JSONPAttribute : ActionFilterAttribute
{
private const string CALL_BACK_QUERY_PARAMETER = "callback";
public override void OnActionExecuted(HttpActionExecutedContext context)
{
string callback;
if (IsJsonp(out callback))
{
var jsonBuilder = new StringBuilder(callback);
jsonBuilder.AppendFormat("({0})", context.Response.Content.ReadAsStringAsync().Result);
context.Response.Content = new StringContent(jsonBuilder.ToString());
}
base.OnActionExecuted(context);
}
private bool IsJsonp(out string callback)
{
callback = HttpContext.Current.Request.QueryString[CALL_BACK_QUERY_PARAMETER];
return !string.IsNullOrEmpty(callback);
}
}
参考:
https://www.cnblogs.com/Vincent-yuan/p/10801513.html
https://docs.microsoft.com/zh-cn/aspnet/core/security/cors