简析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 !=  true return ;
             if  (actionExecutedContext.Response ==  null return ;
             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 ,如需转载请自行联系原作者





相关文章
|
22天前
|
开发框架 .NET 程序员
驾驭Autofac,ASP.NET WebApi实现依赖注入详细步骤总结
Autofac 是一个轻量级的依赖注入框架,专门为 .NET 应用程序量身定做,它就像是你代码中的 "魔法师",用它来管理对象的生命周期,让你的代码更加模块化、易于测试和维护
驾驭Autofac,ASP.NET WebApi实现依赖注入详细步骤总结
|
2月前
|
编解码 数据安全/隐私保护
.Net PdfiumViewer 打印时无法渲染电子签名问题的解决方法
【10月更文挑战第14天】这段内容介绍了使用 PdfiumViewer 库处理 PDF 文件时遇到电子签名无法打印的问题及其解决方法。首先分析了 PdfiumViewer 默认设置或对电子签名支持不足可能导致此问题,建议更新库版本并通过 NuGet 包管理器进行升级。接着检查打印机设置和驱动程序,确保设置正确且驱动为最新版本。然后优化自定义打印代码,提高渲染分辨率,确保电子签名正确加载。最后,验证 PDF 文件格式和兼容性,必要时联系技术支持或求助技术社区。
134 2
|
3月前
|
开发框架 监控 前端开发
在 ASP.NET Core Web API 中使用操作筛选器统一处理通用操作
【9月更文挑战第27天】操作筛选器是ASP.NET Core MVC和Web API中的一种过滤器,可在操作方法执行前后运行代码,适用于日志记录、性能监控和验证等场景。通过实现`IActionFilter`接口的`OnActionExecuting`和`OnActionExecuted`方法,可以统一处理日志、验证及异常。创建并注册自定义筛选器类,能提升代码的可维护性和复用性。
|
4月前
|
前端开发 JavaScript 开发工具
跨域联姻:React.NET——.NET应用与React的完美融合,解锁前后端高效协作新姿势。
【8月更文挑战第28天】探索React.NET,这是将热门前端框架React与强大的.NET后端无缝集成的创新方案。React以其组件化和虚拟DOM技术著称,能构建高性能、可维护的用户界面;.NET则擅长企业级应用开发。React.NET作为桥梁,使.NET应用轻松采用React构建前端,并优化开发流程与性能。通过直接托管React组件,.NET应用简化了部署流程,同时支持服务器端渲染(SSR),提升首屏加载速度与SEO优化。
95 1
|
4月前
|
开发框架 前端开发 .NET
ASP.NET MVC WebApi 接口返回 JOSN 日期格式化 date format
ASP.NET MVC WebApi 接口返回 JOSN 日期格式化 date format
56 0
|
4月前
|
存储 开发框架 .NET
ASP.NET Web Api 使用 EF 6,DateTime 字段如何取数据库服务器当前时间
ASP.NET Web Api 使用 EF 6,DateTime 字段如何取数据库服务器当前时间
|
3月前
|
开发框架 前端开发 JavaScript
ASP.NET MVC 教程
ASP.NET 是一个使用 HTML、CSS、JavaScript 和服务器脚本创建网页和网站的开发框架。
48 7
|
3月前
|
存储 开发框架 前端开发
ASP.NET MVC 迅速集成 SignalR
ASP.NET MVC 迅速集成 SignalR
75 0
|
4月前
|
开发框架 前端开发 安全
ASP.NET MVC 如何使用 Form Authentication?
ASP.NET MVC 如何使用 Form Authentication?
|
4月前
|
开发框架 .NET
Asp.Net Core 使用X.PagedList.Mvc.Core分页 & 搜索
Asp.Net Core 使用X.PagedList.Mvc.Core分页 & 搜索
145 0