开发者社区> 技术小甜> 正文
阿里云
为了无法计算的价值
打开APP
阿里云APP内打开

简析ASP.NET WebApi的跨域签名

简介:
+关注继续查看

要弄清楚 CORS规范将哪些类型的跨域资源请求划分为简单请求的范畴,需要额外了解几个名称的含义,其中包括 “简单 (HTTP)方 法 (Simple Method) “、“简单(请)报头 (Simple Hader)” 和 “ 自定义请求报头 (Author Request Header/ Custom Request Header)” 。 

  CORS规范将GET、HEAD、POST这三个HTTP方法视为“简单HTTP方法”,而将请求报头Accept、Accept-Language、Content-Language以及Content-Type采用Application/X-www-form-urlencoded、multipart/form-data、text/plain的报头称为简单请求报头。

  简而言之,简单请求就是只包含简单请求报头的采用简单方法的Http请求,其他的请求即为费简单请求,如本文提到的跨域签名所需要的签名参数就是添加在HTTP请求的自定义头部里面(如果把签名信息包含在处理函数的参数里面就显得接口签名做的很LOW)。

  跨域其实说的是浏览器的同源策略对JavaScript脚本的Ajax请求的一些限制,阻止程序对脚本请求的数据的操作,而不是阻止请求的发送以及数据的接收,如果用抓包工具查看网络数据的话,其实可以很明显的看到请求的发送,以及接口正常的数据返回。但是为什么浏览器不能正常的处理数据呢?这是因为浏览器需要得到资源提供者的授权之后才会把资源分发给消费者(即JavaScript脚本),而Ajax在进行跨域资源的请求的时候会在报头添加一个“Origin”头部,这个头部的值就是当前发起请求的域。因此想要解决简单请求的跨域问题只需要对请求报文中的Origin的值进行处理,对已授权的域的响应添加一个响应报头"Access-Control-Allow-Origin",一般对授权域的响应报头"Access-Control-Allow-Origin"值置为“*”。而非简单请求的跨域调用流程就跟简单报文的调用流程有所差异呢,在发送非简单报文时,浏览器就会采用“预检”机制来完成非简单请求的跨域资源请求。所谓预检机制就是浏览器在发送真正的跨域资源请求前 ,先发送一个预检请求(PreflightRequest)。 预检请求为一个采用0PTIONS方法的请求,这是一个不包含主体的请求,用户凭证相关的报头也会被剔除。基于真正资源请求的一些辅助授权的信息会包含在此预检请求的响应报头中。 除了代表请求页面所在站点的 “Origin” 报头之外,如 下所示的是两个典型的请求报头 。
● Access-Control-Request-Method:跨域资源请求采用的HTTP方 法 。
● Access-Control-Request-Headers:跨域资源请求携带的自定义报头列表 。
资源的提供者在接收到预检请求之后会根据其提供的相关报头进行授权检验 ,具体的检验逻辑包括确定请求站点是否值得信任 ,以及请求采用HTTP方法和自定义报头是否被允许 。如果预检请求没有通过授权检验 ,资源提供者一般会返回一个状态为“400,Bad Reuqest”的响应(也可自定义返回报文消息,如本文) 。 反之则会返回一个状态为 “200,OK” 的响应(也可自定义返回报文消息) ,授权相关信息会包含在响应报头中。
除了上面介绍的 “Access-Control-Allow-Origin” 和 “Access-Control-Allow-Method” 报头之外,预检请求的响应还具有如下 3个典型的报头。
● Access-Control-Allow-Method:跨域资源请求允许采用 的 HTTP方法列表 。
● Access-Control-Allow-Headers:跨域资源请求允许携带的自定义报头列表 。

● Access-Control-Max-Age:浏览器可以将响应结果进行缓存的时间 (单位为秒 ),这样可以让浏览器避免频繁地发送预检请求 。

如果预检请求满足如下三个条件,浏览器则认为后续将要发送的跨域资源请求是被授权的

● 通过请求的 “Origin” 报头表示的源站点必须存在于 “Access-Control-Allow-Origin响应报头标识的站点列表中。

预检请求的 “Access-Control-Request-Headers” 报头存储的报头名称均在响应报头“Access-Control-Allow-Headers” 表示的报头列表之内。

预检请求的“Access-Control-Request-Method” 报头表示的请求方法在预检请求响应报文“Access-Control-Allow-Methods”表示的列表之内。   

  因此以上可知:想要完成非简单报文的跨域请求,就必须要在服务器端对预检请求进行正常的应答,当收到预检请求时,对其进行正常的响应,这就需要在应答报文中添加“Access-Control-Allow-Origin”、“Access-Control-Allow-Methods”、“Access-Control-Allow-Headers”,这三个自定义报文头,同时这三个报文头要按照预检机制的要求进行填充。尤其是“Access-Control-Allow-Headers”自定义头部列表要包含签名所需的所有自定义头部名。

  以上便是对跨域、预检机制以及其解决方法的描述,接下来讲实际的处理方法

  (1)跨域支持:对控制器添加一个Filter属性并重写OnActionExecuted方法,向响应报文添加自定义头部。

    (2)预检报文应答:因为一般的API控制器都没有实现OPTIONS方法,而预检报文的请求方法是OPTIONS,因此需要我们实现OPTION方法。至于每个控制器多了一个平时都不使用的OPTIONS方法,写在那里难看,这就是系统架构要考虑的问题了,这里我们只说具体问题的具体解决方法。

  (3)接口签名验证:对控制器添加一个Filter属性对自定义报文进行自己的验证逻辑,这个就随意发挥了。 

  跨域的预检报文支持代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
    /// <summary>
    /// 添加跨域支持
    /// </summary>
    public class EnableCors : ActionFilterAttribute
    {
        /// <summary>
        /// 操作标记
        /// </summary>
        private bool Flag { get;  set; }
 
        /// <summary>
        /// 默认构造函数 true:开启跨域 false:关闭跨域支持
        /// </summary>
        /// <param name="para"></param>
        public EnableCors(bool para)
        {
            Flag = para;
        }
 
        /// <summary>
        /// 方法执行之后执行
        /// </summary>
        /// <param name="actionExecutedContext"></param>
        public override void OnActionExecuted(HttpActionExecutedContext actionExecutedContext)
        {
            base.OnActionExecuted(actionExecutedContext);
            if (Flag != truereturn;
            if (actionExecutedContext.Response == nullreturn;
            if (actionExecutedContext.Response.Headers.Contains("Access-Control-Allow-Origin"))
            {
                actionExecutedContext.Response.Headers.Remove("Access-Control-Allow-Origin");
            }
            if (actionExecutedContext.Response.Headers.Contains("Access-Control-Allow-Method"))
            {
                actionExecutedContext.Response.Headers.Remove("Access-Control-Allow-Method");
            }
            if (actionExecutedContext.Response.Headers.Contains("Access-Control-Allow-Headers"))
            {
                actionExecutedContext.Response.Headers.Remove("Access-Control-Allow-Headers");
            }
            actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Origin""*");
            actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Methods""GET, POST, PUT, DELETE, OPTIONS");
            actionExecutedContext.Response.Headers.Add("Access-Control-Allow-Headers""Content-Type,TimeStamp,Parameter,RandNum");
        }
    }

  接口签名代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
   /// <summary>
    /// 接口签名属性
    /// </summary>
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class ApiAuthorization : AuthorizationFilterAttribute
    {
        public override void OnAuthorization(HttpActionContext actionContext)
        {
            base.OnAuthorization(actionContext);
            if (actionContext.Request.Method == HttpMethod.Options) return;//支持跨域的自定义报头请求(预检机制)
            //TODO这里就是接口签名的代码,可以取自定义头部进行处理,签名通过则直接return,否则对actionContext.Response进行赋值,表示签名失败后面的操作不执行
            actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Forbidden, new CheckResult() { Result = false, Message = "Access denied!" }); 
        }
    }

  

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
    /// <summary>
    /// 基础控制器
    /// </summary>
    [DataType(ApiDataType.Json)]
    [EnableCors(true)]
    [Description("Api基础控制器")]
    [ApiAuthorization]
    public class ApiBaseController : ApiController
    {
        /// <summary>
        /// 为了支持ajax跨域的预检机制
        /// </summary>
        public void  Options()
        {
        }
    }

  通过以上步骤就完成了跨域的预检报文应答,接口签名。实际运行效果如下图所示:

  首先我发送一个非简单报文的操作,我通过Fiddler实际抓到了两个包,第一个就是上面所说的预检报文,第二个才是包含我们所有自定义报文头部的实现我们真正跨域资源请求的报文。

  而预检请求报文以及应答报文的信息如图(格式也如上文所讲):

  跨域资源请求报文及其应答报文如下(注意我们用于接口签名的自定义报文头):

  下面来一个正常通过跨域操作,并且签名验证失败的报文,同样是一个预检报文,一个正式报文















本文转自xmgdc51CTO博客,原文链接:http://blog.51cto.com/12953214/1944096 ,如需转载请自行联系原作者





版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
ASP.NET WebAPi之断点续传下载(下)
前言 上一篇我们穿插了C#的内容,本篇我们继续来讲讲webapi中断点续传的其他情况以及利用webclient来实现断点续传,至此关于webapi断点续传下载以及上传内容都已经全部完结,一直嚷嚷着把SQL Server和Oracle数据库再重新过一遍,这篇过完,就要开始新的征程,每一个阶段都应该有自己的小目标,要不然当工作太忙没时间去充电,太闲又变得懒散,想想一切是为了未来买得起孩子高档的奶粉就又有动力了。
1088 0
ASP.NET WebAPi之断点续传下载(中)
前言 前情回顾:上一篇我们遗留了两个问题,一个是未完全实现断点续传,另外则是在响应时是返回StreamContent还是PushStreamContent呢?这一节我们重点来解决这两个问题,同时就在此过程中需要注意的地方一并指出,若有错误之处,请指出。
1090 0
ASP.NET WebAPi之断点续传下载(上)
前言 之前一直感觉断点续传比较神秘,于是想去一探究竟,不知从何入手,以为就写写逻辑就行,结果搜索一番,还得了解相关http协议知识,又花了许久功夫去看http协议中有关断点续传知识,有时候发觉东西只有当你用到再去看相关内容时才会掌握的更加牢固,理解的更加透彻吧,下面我们首先来补补关于http协议中断点续传的知识。
1040 0
ASP.NET自定义控件组件开发 第一章 第三篇
原文:ASP.NET自定义控件组件开发 第一章 第三篇                                             第三篇:第一章的完结篇     系列文章链接: ASP.
889 0
ASP.NET自定义控件组件开发 第一章 第二篇 接着待续
原文:ASP.NET自定义控件组件开发 第一章 第二篇 接着待续      ASP.NET自定义控件组件开发 第一章 第二篇 接着待续     很感谢大家给我的第一篇ASP.NET控件开发的支持!在写这些之前,我也看了一些例子,想选中一些好上手的例子,这样,可能一些例子大家以前都见过,但是我想说:同样是弹钢琴,同样一首“命运交响曲”,有的人弹的让人荡气回肠,有的人弹的就很一般。
922 0
一起谈.NET技术,asp.net控件开发基础(10)
  集合属性相信大家都很熟悉也很常用,如DropDownList,ListBox等控件             测试1            测试2            测试3           1.实现集合属性效果   经过前面几篇的学习,相信这一篇看起来已经相对简单了.我们要做的就是,先定义一个复杂属性,然后用迭代语句获取数组数据即可。
772 0
+关注
文章
问答
文章排行榜
最热
最新
相关电子书
更多
低代码开发师(初级)实战教程
立即下载
阿里巴巴DevOps 最佳实践手册
立即下载
冬季实战营第三期:MySQL数据库进阶实战
立即下载