一、同源策略和资源跨域共享

 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源码还是比较简单的,很容易看懂。可以自己写一个项目,然后挂上源码单步调试。

转载于:https://www.cnblogs.com/MicroHeart/p/9298759.html

.Net Core Cors中间件解析相关推荐

  1. 《ASP.NET Core In Action》读书笔记系列五 ASP.NET Core 解决方案结构解析1

    <ASP.NET Core In Action>读书笔记系列五 ASP.NET Core 解决方案结构解析1 参考文章: (1)<ASP.NET Core In Action> ...

  2. .net core 源码解析-mvc route的注册,激活,调用流程(三)

    .net core mvc route的注册,激活,调用流程 mvc的入口是route,当前请求的url匹配到合适的route之后,mvc根据route所指定的controller和action激活c ...

  3. .Net Core 源码解析

    .Net core 源码解析 启动代码 创建并配置主机Builder CreateDefaultBuilder分析 Host类-用于产生初始的builder静态类 IHostBuilder转变成IWe ...

  4. 渗透测试-中间件解析漏洞分析

    中间件解析漏洞分析 文章目录 中间件解析漏洞分析 前言 一.什么是解析漏洞 二.解析漏洞基本原理以及利用实例 1. 解析漏洞基本原理及实例 总结 前言 一.什么是解析漏洞 文件解析漏洞主要由于网站管理 ...

  5. Asp.Net.Core 系列-中间件和依赖注入进阶篇

    上一节讲了中间件和依赖注入的基础,紧接着: 中间件是怎么使用的?使用步骤是什么? 只要把中间件注册到管道中就行了,可以借助Startup对象(DelegateStartup或者ConventionBa ...

  6. .net core 源码解析-web app是如何启动并接收处理请求

    最近.net core 1.1也发布了,蹒跚学步的小孩又长高了一些,园子里大家也都非常积极的在学习,闲来无事,扒拔源码,涨涨见识. 先来见识一下web站点是如何启动的,如何接受请求,.net core ...

  7. aspnetcore mvc 异常处理_深入探究ASP.NET Core异常处理中间件

    前言 全局异常处理是我们编程过程中不可或缺的重要环节.有了全局异常处理机制给我们带来了很多便捷,首先我们不用满屏幕处理程序可能出现的异常,其次我们可以对异常进行统一的处理,比如收集异常信息或者返回统一 ...

  8. .net core 源码解析-web app是如何启动并接收处理请求(二) kestrel的启动

    上篇讲到.net core web app是如何启动并接受请求的,下面接着探索kestrel server是如何完成此任务的. 1.kestrel server的入口KestrelServer.Sta ...

  9. 深入探究ASP.NET Core异常处理中间件

    前言 全局异常处理是我们编程过程中不可或缺的重要环节.有了全局异常处理机制给我们带来了很多便捷,首先我们不用满屏幕处理程序可能出现的异常,其次我们可以对异常进行统一的处理,比如收集异常信息或者返回统一 ...

最新文章

  1. 加快LOOP嵌套循环的一个方法
  2. linux下文件操作
  3. 深度学习数学相关知识
  4. IOS开发报错之Undefined symbols for architecture armv6
  5. linux监控哪些目录,linux管理文件和目录的命令
  6. 求职产品经理【十六】笔试真题串讲之百度地图与大数据结合的产品
  7. 本地存储之sessionStorage
  8. mysql 搭建日志服务器_一、架构01-搭建日志服务器Rsyslog
  9. 学习python入门的个人建议及资料
  10. python生成数据库登录界面_python 生成数据库
  11. [Android]使用Dagger 2依赖注入 - 自定义Scope(翻译)
  12. pytorch提取softmax前的特征并保存为txt文件
  13. CRACK小试牛刀:关于GALGAME银色遥远爆破记录
  14. 此windows7副本不是正版、黑屏7601的解决办法
  15. 服务器中修改数据库配置,服务器修改数据库配置未生效
  16. 走进大数据丨 一条让我虎躯一震的SQL
  17. python职能-python运维工程师主要干什么
  18. MySQL数据库基础——强大的select之二,更加精彩的功能
  19. 360搜索结果页html代码,360搜索抓取完全封闭网页揭秘
  20. 集成学习 hard/soft Voting,Bagging/Pasting,oob 随机森林

热门文章

  1. 翻译 | 摆脱浏览器限制的JavaScript
  2. Android推送进阶课程学习笔记
  3. es6 匿名函数求阶乘
  4. 『创建型』简单工厂SimpleFactory、工厂方法FactoryMethod、抽象工厂AbstractFactory
  5. Spring MVC使用拦截器实现权限控制
  6. Hasor:生命周期
  7. case when是不是只要满足第一个别的就不进行执行了
  8. 面对众多的前端框架,你该如何学习?
  9. apply plugin: 'idea' --- gradle idea
  10. 关于PostgreSQL的GiST索引之四