.Net Core Cors中间件解析

Posted Donet技术联盟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了.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)

  • AJAX请求不能被发送(AJAX请求只能发送给同源的网址)

  要知道一点,这些限制其实都是浏览器做的限制。

 2、跨域资源共享

  跨域资源共享跟同源策略相反。在整个跨域通信过程中,浏览器会自动识别此次请求是否跨域,一旦发现跨域,就自动添加请求头信息(如Origin)或者自动发送一次请求方式为option的预请求。浏览器将CORS请求分为两类:简单请求和非简单请求。

 2.1、简单请求

  当浏览器的请求方式是Head、Get或者Post,并且HTTP的头信息中不会超出以下字段:

  • Accept

  • Accept-Language

  • Content-Language

  • Origin

 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请求)
.Net Core Cors中间件解析

                                           (第二次请求)

二、服务端实现CORS

  在.Net Core Web Api中使用很简单,首先安装包Microsoft.AspNet.WebApi.Cors,在StartUp中添加下面两句

.Net Core Cors中间件解析

        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();        }

.Net Core Cors中间件解析

在使用的时候只需要在Controller或者Action中加上特性[EnableCors("CorsTest")]

.Net Core Cors中间件解析

    [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" };
        }
    }

.Net Core Cors中间件解析

现在服务端已经配置好了,现在需要通过前端跨域请求

.Net Core Cors中间件解析

<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>

.Net Core Cors中间件解析

测试结果如下图:

.Net Core Cors中间件解析

                          (options请求)

.Net Core Cors中间件解析

                        (第二次请求)

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请求都会调用这个方法。

.Net Core Cors中间件解析

     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中间件解析的主要内容,如果未能解决你的问题,请参考以下文章

.Net Core CORS 因自定义中间件而失败 [重复]

.net core api CORS 获得工作,但 cors 获得 405

Asp.Net Core 允许 CORS 中的 IP 范围

.NET Core 端点 + 全局 CORS

从我的自定义中间件返回到角度时,asp .net core api cors 问题

.Net Core 3.0 Api json web token 中间件签权验证和 CORS 中间件处理跨域请求