音效素材网提供各类素材,打造精品素材网站!

站内导航 站长工具 投稿中心 手机访问

音效素材

.Net Core Cors中间件的深入讲解
日期:2021-09-07 22:36:45   来源:脚本之家

同源策略和资源跨域共享

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中,在请求(第一次请求)返回的时候将这些加到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源码还是比较简单的,很容易看懂。可以自己写一个项目,然后挂上源码单步调试。

总结

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。

    您感兴趣的教程

    在docker中安装mysql详解

    本篇文章主要介绍了在docker中安装mysql详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编...

    详解 安装 docker mysql

    win10中文输入法仅在桌面显示怎么办?

    win10中文输入法仅在桌面显示怎么办?

    win10系统使用搜狗,QQ输入法只有在显示桌面的时候才出来,在使用其他程序输入框里面却只能输入字母数字,win10中...

    win10 中文输入法

    一分钟掌握linux系统目录结构

    这篇文章主要介绍了linux系统目录结构,通过结构图和多张表格了解linux系统目录结构,感兴趣的小伙伴们可以参考一...

    结构 目录 系统 linux

    PHP程序员玩转Linux系列 Linux和Windows安装

    这篇文章主要为大家详细介绍了PHP程序员玩转Linux系列文章,Linux和Windows安装nginx教程,具有一定的参考价值,感兴趣...

    玩转 程序员 安装 系列 PHP

    win10怎么安装杜比音效Doby V4.1 win10安装杜

    第四代杜比®家庭影院®技术包含了一整套协同工作的技术,让PC 发出清晰的环绕声同时第四代杜比家庭影院技术...

    win10杜比音效

    纯CSS实现iOS风格打开关闭选择框功能

    这篇文章主要介绍了纯CSS实现iOS风格打开关闭选择框,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作...

    css ios c

    Win7如何给C盘扩容 Win7系统电脑C盘扩容的办法

    Win7如何给C盘扩容 Win7系统电脑C盘扩容的

    Win7给电脑C盘扩容的办法大家知道吗?当系统分区C盘空间不足时,就需要给它扩容了,如果不管,C盘没有足够的空间...

    Win7 C盘 扩容

    百度推广竞品词的投放策略

    SEM是基于关键词搜索的营销活动。作为推广人员,我们所做的工作,就是打理成千上万的关键词,关注它们的质量度...

    百度推广 竞品词

    Visual Studio Code(vscode) git的使用教程

    这篇文章主要介绍了详解Visual Studio Code(vscode) git的使用,小编觉得挺不错的,现在分享给大家,也给大家做个参考。...

    教程 Studio Visual Code git

    七牛云储存创始人分享七牛的创立故事与

    这篇文章主要介绍了七牛云储存创始人分享七牛的创立故事与对Go语言的应用,七牛选用Go语言这门新兴的编程语言进行...

    七牛 Go语言

    Win10预览版Mobile 10547即将发布 9月19日上午

    微软副总裁Gabriel Aul的Twitter透露了 Win10 Mobile预览版10536即将发布,他表示该版本已进入内部慢速版阶段,发布时间目...

    Win10 预览版

    HTML标签meta总结,HTML5 head meta 属性整理

    移动前端开发中添加一些webkit专属的HTML5头部标签,帮助浏览器更好解析HTML代码,更好地将移动web前端页面表现出来...

    移动端html5模拟长按事件的实现方法

    这篇文章主要介绍了移动端html5模拟长按事件的实现方法的相关资料,小编觉得挺不错的,现在分享给大家,也给大家...

    移动端 html5 长按

    HTML常用meta大全(推荐)

    这篇文章主要介绍了HTML常用meta大全(推荐),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参...

    cdr怎么把图片转换成位图? cdr图片转换为位图的教程

    cdr怎么把图片转换成位图? cdr图片转换为

    cdr怎么把图片转换成位图?cdr中插入的图片想要转换成位图,该怎么转换呢?下面我们就来看看cdr图片转换为位图的...

    cdr 图片 位图

    win10系统怎么录屏?win10系统自带录屏详细教程

    win10系统怎么录屏?win10系统自带录屏详细

    当我们是使用win10系统的时候,想要录制电脑上的画面,这时候有人会想到下个第三方软件,其实可以用电脑上的自带...

    win10 系统自带录屏 详细教程

    + 更多教程 +
    ASP编程JSP编程PHP编程.NET编程python编程