.Net Core Cors中间件解析
一、同源策略和资源跨域共享
1、同源策略
同源策略,它是由Netscape提出的一个著名的安全策略。现在所有支持JavaScript 的浏览器都会使用这个策略。所谓同源是指,域名,协议,端口相同。
1.1、目的
主要是为了保证用户信息的安全,防止网站窃取用户数据。假如没有同源策略,可能就会有下面这种情况的发生。用户访问两个网站A/B,并登录了A网站,A网站会在计算机本地存储Cookie或者Token等等,在访问B网站的时候,B网站就可以访问这些本地的存储信息,B网站可以使用用户的Cookie去登录A网站,那这样用户信息就被泄露了。
1.2、限制范围
- Cookie、LocalStorage和indexDB无法访问(只有同源的网页才能共享Cookie)
- DOM无法获得(父窗口和子窗口的地址是同源的才能获取子窗口的信息)
- AJAX请求不能被发送(AJAX请求只能发送给同源的网址)
要知道一点,这些限制其实都是浏览器做的限制。
2、跨域资源共享
跨域资源共享跟同源策略相反。在整个跨域通信过程中,浏览器会自动识别此次请求是否跨域,一旦发现跨域,就自动添加请求头信息(如Origin)或者自动发送一次请求方式为option的预请求。浏览器将CORS请求分为两类:简单请求和非简单请求。
2.1、简单请求
当浏览器的请求方式是Head、Get或者Post,并且HTTP的头信息中不会超出以下字段:
Accept
Accept-Language
Content-Language
Origin
时,浏览器会将该请求定义为简单请求,否则就是非简单请求。当浏览器判断为简单请求后,浏览器会自动再请求报文头中加上Origin字段,表明此次请求来自的地址(协议+域名+端口)。然后服务器需要去判断是否接受这个来源的请求。如果允许服务器端返回的头部中需要有Access-Control-Allow-Origin,其值为请求时Origin字段的值或*(表示接受任意源的请求)。请求头中还会有Access-Control-Allow-Methods表示服务器允许的跨域请求的方式。Access-Control-Allow-Headers表示请求头中允许出现的字段。
2.2、 非简单请求
当浏览器判断为非简单请求后,会发送两次请求,首先浏览器会自动发送一个请求方式为options的请求,并在请求头中
- 加上Access-Control-Request-Method表示下次请求的方法,
- 加上Origin表明来源,
- 加上Access-Control-Request-Headers表示下次请求的请求头中额外的字段。
服务器收到请求后,需要获取这三个请求头中的值,并进行判断,确认是否允许进行跨域。如果服务器返回的请求头中没有任何CORS相关的请求头信息,浏览器会认为不通过预检,也不会进行第二次请求。
服务器如果接受跨域并验证通过了options的请求,会返回Access-Control-Allow-Origin(表明允许跨域请求的源)、Access-Control-Allow-Methods(允许跨域请求的请求方式)、Access-Control-Allow-Headers(允许请求头中包含的额外字段)。然后浏览器才会发送真正的请求。
(第一次options请求)
(第二次请求)
二、服务端实现CORS
在.Net Core Web Api中使用很简单,首先安装包Microsoft.AspNet.WebApi.Cors,在StartUp中添加下面两句
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
//添加Cors,并配置CorsPolicy
services.AddCors(options => options.AddPolicy("CorsTest", p => p.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()));
} public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
//注意UseCors()要在UseMvc()之前
app.UseCors("CorsTest");
app.UseMvc();
}
在使用的时候只需要在Controller或者Action中加上特性[EnableCors("CorsTest")]
[EnableCors("CorsTest")]
public class ValuesController : Controller
{
private ILogger<ValuesController> _logger;
public ValuesController(ILogger<ValuesController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<string> Get()
{
return new string[] { "value1", "value2" };
}
}
现在服务端已经配置好了,现在需要通过前端跨域请求
<html>
<head>
测试
</head>
<body>
测试
</body>
</html>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
<script type="text/javascript">
$(function () {
$.ajax({
type: "get",
url: "http://localhost:7000/api/values",
beforeSend: function (request) {//在请求报文头中加入Authorization 目的是让请求为非简单请求
request.setRequestHeader("Authorization", "Bearer 071899A00D4D4C5B1C41A6B0211B9399");
},
success: function (result) {
alert(result);
}
}, "json");
});
</script>
测试结果如下图:
(options请求)
(第二次请求)
上面配置允许所有的地址请求这个接口,也可以单独配置某个地址。
services.AddCors(options => options.AddPolicy("CorsTest", p => p.WithOrigins("http://localhost:8089")
.AllowAnyHeader()
.AllowAnyMethod()));
三、解析Cors源码
打开CORS源码,主要的是CorsMiddleware、CorsOptions、CorsPolicy、CorsPolicyBuilder、CorsResult、CorsService这几个类。
- CorsPolicy:就是我们在Startup中的配置,如允许哪些域名可以跨域请求,允许哪些跨域请求方式,允许哪些额外的请求头,每个配置对应一个名称。
services.AddCors(options => options.AddPolicy("CorsTest", p => p.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()));
- CorsOptions:中包含一个字典IDictionary<string, CorsPolicy> PolicyMap,一个项目可能有过个Cors配置,所以这个CorsOptions就是通过配置名称管理这些配置的。
- CorsPolicyBuilder:通过它来构造CorsPolicy。
- CorsResult:是验证跨域过程得到的结果。如在第一次Options请求时,客户端发送了Origi:http://localhost:8089,服务器会返回Access-Control-Allow-Origin:http://localhost:8089。过程是这样的:服务器验证http://localhost:8089这个域名是否允许跨域,如果允许就将“http://localhost:8089”这个值存储到CorsResult的AllowedHeaders中,在Options请求返回的时候将这个值加到HTTP请求头Access-Control-Allow-Origin中。说白了 就是通过CorsResult的内容组装HTTP的响应头。
- CorsMiddleware:Cors中间件类,主要方法就是Invoke,每次HTTP请求都会调用这个方法。
public async Task Invoke(HttpContext context)
{//判断HTTP请求头是否有Origin,由此判断是不是跨域请求
if (context.Request.Headers.ContainsKey(CorsConstants.Origin))
{
var corsPolicy = _policy ?? await _corsPolicyProvider?.GetPolicyAsync(context, _corsPolicyName);
if (corsPolicy != null)
{
var accessControlRequestMethod = context.Request.Headers[CorsConstants.AccessControlRequestMethod];
//如果是跨域请求 判断是不是第一次Options请求
if (string.Equals(context.Request.Method,CorsConstants.PreflightHttpMethod,StringComparison.OrdinalIgnoreCase)
&&!StringValues.IsNullOrEmpty(accessControlRequestMethod))
{
//判断是否允许当前请求跨域,根据HttpContext的内容和Cors配置 得到CorsResult,然后将CorsResult的内容添加到请求头中(看下面详细解释)
ApplyCorsHeaders(context, corsPolicy);
context.Response.StatusCode = StatusCodes.Status204NoContent;
return;
}
else
{// 执行第二次非Options请求
context.Response.OnStarting(state =>
{
var (httpContext, policy) = (Tuple<HttpContext, CorsPolicy>)state;
try
{
ApplyCorsHeaders(httpContext, policy);
}
catch (Exception exception)
{
_logger.FailedToSetCorsHeaders(exception);
}
return Task.CompletedTask;
}, Tuple.Create(context, corsPolicy));
}
}
}
await _next(context);
}
private void ApplyCorsHeaders(HttpContext context, CorsPolicy corsPolicy)
{ //通过HTTP上下文请求的数据和Cors配置 得到CorsResult
如在第一次Options请求时,客户端发送了Origi:http://localhost:8089,Access-Control-Resquest-Methods:GET
服务器会返回Access-Control-Allow-Origin:http://localhost:8089,Access-Control-Allow-Methods:GET
服务器验证http://localhost:8089这个域名以GET请求方式是否允许跨域,
如果允许就将“http://localhost:8089”这个值存储到CorsResult的AllowedHeaders中
将"GET"存储到CorsResult的AllowedMethods中
var corsResult = _corsService.EvaluatePolicy(context, corsPolicy);
//将CorsResult中的值添加到相应头中的,返回到客户端
_corsService.ApplyResult(corsResult, context.Response);
}
相对来说Cors源码还是比较简单的,很容易看懂。可以自己写一个项目,然后挂上源码单步调试。
.Net Core Cors中间件解析的更多相关文章
- 数据库表设计时一对一关系存在的必要性 数据库一对一、一对多、多对多设计 面试逻辑题3.31 sql server 查询某个表被哪些存储过程调用 DataTable根据字段去重 .Net Core Cors中间件解析 分析MySQL中哪些情况下数据库索引会失效
数据库表设计时一对一关系存在的必要性 2017年07月24日 10:01:07 阅读数:694 在表设计过程中,我无意中觉得一对一关系觉得好没道理,直接放到一张表中不就可以了吗?真是说,网上信息什么都 ...
- asp.net core cors中间件
public class CorsMiddleware { private readonly RequestDelegate _next; public CorsMiddleware(RequestD ...
- .Net Core 3.0 Api json web token 中间件签权验证和 Cors 中间件处理跨域请求
第一步:在Nuget上安装"Microsoft.AspNet.WebApi.Cors"包,并对api controller使用[EnableCors]特性以及Microsoft.A ...
- Asp.net Core CORS(跨域资源共享)实验
环境:Asp.Net Core 2 1.问题 最近项目在调用远程UI时遇到点麻,在调用远程CSS文件时无法加载其中的字体文件.远程CSS文件对字体的定义: @font-face { font-fami ...
- ASP.NET Core路由中间件[2]: 路由模式
一个Web应用本质上体现为一组终结点的集合.终结点则体现为一个暴露在网络中可供外界采用HTTP协议调用的服务,路由的作用就是建立一个请求URL模式与对应终结点之间的映射关系.借助这个映射关系,客户端可 ...
- 如何传递参数给ASP.NET Core的中间件(Middleware)
问题描述 当我们在ASP.NET Core中定义和使用中间件(Middleware)的时候,有什么好的办法可以给中间件传参数吗? 解决方案 在ASP.NET Core项目中添加一个POCO类来传递参数 ...
- asp.net core mvc 中间件之WebpackDevMiddleware
asp.net core mvc 中间件之WebpackDevMiddleware WebpackDevMiddleware中间件主要用于开发SPA应用,启用Webpack,增强网页开发体验.好吧,你 ...
- asp.net core mvc 中间件之路由
asp.net core mvc 中间件之路由 路由中间件 首先看路由中间件的源码 先用httpContext实例化一个路由上下文,然后把中间件接收到的路由添加到路由上下文的路由集合 然后把路由上下文 ...
- 如何在ASP.NET Core自定义中间件中读取Request.Body和Response.Body的内容?
原文:如何在ASP.NET Core自定义中间件中读取Request.Body和Response.Body的内容? 文章名称: 如何在ASP.NET Core自定义中间件读取Request.Body和 ...
随机推荐
- 找不到phpize
yum install php-devel 报错如下: 解决办法: yum install php71w-devel
- solr7.7.0搜索引擎使用(三)(添加文件索引)
众所周知,solr与es的最大区别是,solr可以对pdf,txt,doc等文件生成索引 那我们如何添加文件索引呢? 步骤1.添加core,取名暂且为 coreFile 在bin下执行命令 ./sol ...
- W7500P硬件TCP/IP+硬件物理层PHY+Cortex-M0处理器(48MHZ)
W7500P 硬件TCP/IP+硬件物理层PHY+Cortex-M0处理器(48MHZ) 硬件TCP/IP+硬件物理层PHY+Cortex-M0处理器(48MHZ) 如果您发现商品信息不准确,欢迎纠错 ...
- selenium中动作链的使用
一.问题 我们有时候在使用selenium的时候,会遇到悬停后点击元素的操作,因此需要一个动作链来完成这个功能. 二.解决 从selenium的包中导入actionchains函数,利用xpath找到 ...
- Java面试题4
一.JAVA基础篇-概念1.简述你所知道的Linux: Linux起源于1991年,1995年流行起来的免费操作系统,目前, Linux是主流的服务器操作系统, 广泛应用于互联网.云计算.智能手机(A ...
- 2017-2018-1 20155205 嵌入式C语言——时钟
2017-2018-1 20155205 嵌入式C语言--时钟 题目要求 基础知识 插入位(以分钟为例) 提取位(以分钟为例) 在提取分钟时,运用到了位运算,位运算有以下规律: &0 --&g ...
- Python-字典(dict)
字典是一种key-value的数据类型,字典里必须写Key和value: 字典的优点是取数方便和速度快. 字典的定义使用大括号{ },每个值用“,”隔开,key和value使用“:”分隔. value ...
- 网页中的数据的4个处理方式:CRUD(Creat, Retrive, Update, Delete)
网页中的数据的4个处理方式:CRUD(Creat, Retrive, Update, Delete) 2018-12-21, 后续完善
- 学习tableauhttps://www.tableau.com/zh-cn/learn/training
入门教程不错: https://www.tableau.com/zh-cn/learn/training
- 连接SSH服务器的脚本,自动发送用户名和密码
利用expect 自动输入用户名和密码 脚本如下 #!/usr/bin/expect # connect ssh server set timeout 30 spawn ssh -l user_nam ...