简析ASP.NET WebApi的跨域签名
之前的文章写了关于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属性对自定义报文进行自己的验证逻辑,这个就随意发挥了。
跨域的预检报文支持代码:
/// <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");
}
}
接口签名代码:
/// <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!" });
}
}
/// <summary>
/// 基础控制器
/// </summary>
[DataType(ApiDataType.Json)]
[EnableCors(true)]
[Description("Api基础控制器")]
[ApiAuthorization]
public class ApiBaseController : ApiController
{
/// <summary>
/// 为了支持ajax跨域的预检机制
/// </summary>
public void Options()
{
}
}
通过以上步骤就完成了跨域的预检报文应答,接口签名。实际运行效果如下图所示:
首先我发送一个非简单报文的操作,我通过Fiddler实际抓到了两个包,第一个就是上面所说的预检报文,第二个才是包含我们所有自定义报文头部的实现我们真正跨域资源请求的报文。

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

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

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

简析ASP.NET WebApi的跨域签名的更多相关文章
- ASP.NET WebAPI解决跨域问题
跨域是个很蛋疼的问题...随笔记录一下... 一.安装nuget包:Microsoft.AspNet.WebApi.Core 二.在Application_Start方法中启用跨域 1 protect ...
- 为Asp.net WebApi 添加跨域支持
Nuget安装包:microsoft.aspnet.webapi.cors 原文地址:https://www.asp.net/web-api/overview/security/enabling-cr ...
- asp.net webapi支持跨域
1.Install-Package Microsoft.AspNet.WebApi.Cors 2. using System.Web.Http; namespace WebService { ...
- asp.net core webapi之跨域(Cors)访问
这里说的跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协议.域名.端口有任何一个不同,都被当作 ...
- 关于WebService、WebApi的跨域问题
随着移动互联网的发展, 传统营销模式往网站以及移动客户端转移已经成为一种趋势.接触过互联网开发的开发者肯定会很熟悉两种网络服务WebApi.WebService.在使用JavaScript进行数据交互 ...
- .NET压缩图片保存 .NET CORE WebApi Post跨域提交 C# Debug和release判断用法 tofixed方法 四舍五入 (function($){})(jQuery); 使用VUE+iView+.Net Core上传图片
.NET压缩图片保存 需求: 需要将用户后买的图片批量下载打包压缩,并且分不同的文件夹(因:购买了多个用户的图片情况) 文章中用到了一个第三方的类库,Nuget下载 SharpZipLib 目前用 ...
- ASP.NET中Cookie跨域的问题及解决代码
ASP.NET中Cookie跨域的问题及解决代码 http://www.liyumei.net.cn/post/share18.html Cookies揭秘 http://www.cnblogs.c ...
- asp.net core webapi Session 跨域
在ajax 请求是也要加相应的东西 $.ajax({ url:url, //加上这句话 xhrFields: { withCredentials: true } success:function(re ...
- asp.net core webapi 配置跨域处理
在Startup.cs文件中的ConfigureServices方法中加入如下代码: //配置跨域处理 services.AddCors(options => { options.AddPoli ...
随机推荐
- 基于AGS JS开发自定义贴图图层
文章版权由作者李晓晖和博客园共有,若转载请于明显处标明出处:http://www.cnblogs.com/naaoveGIS/ 1.前言 假设一个景区有多张图片需要在地图上展示,并且随着地图的缩放而缩 ...
- hibernate 三种状态的转换
一.遇到的神奇的事情 使用jpa操作数据库,当我使用findAll()方法查处一个List的对象后,给对这个list的实体进行了一些操作,并没有调用update 或者 saveOrUpdate方法,更 ...
- angularjs fileUpload
文件上传一直是我不熟悉的地方,<a href='https://github.com/nervgh/angular-file-upload/wiki/Module-API'>官网解释的例子 ...
- TCP的连接和建立 图解
前言 在没有理解TCP连接是如何建立和终止之前,我想你可能并不会使用connect,accept,close这三个函数并且使用netstat程序来调试应用.所以掌握TCP连接的建立和终止势在必行. 三 ...
- java对String进行sha1加密
1.使用apache的codec jar包对string进行加密,先下载并引入jar包: http://commons.apache.org/proper/commons-codec/ 2.生成: S ...
- vue2.0自定义指令的使用方法
感觉2.0好坑啊,自定义指令和1.0完全不一样,并且文档写得也不太清晰,下面是我写得一个demo,希望帮助大家更好地理解自定义指令 <!DOCTYPE html> <html lan ...
- linux下PHP 环境搭建
linux下环境搭建 第一步 安装Apache2 sudo apt-get install apache2 第二步 安装PHP模块 sudo apt-get install php5 第三 ...
- 转接口IC NCS8807:LVDS转MINI LVDS芯片
LVDS 4K TCON w/ Scaler1 General Description NCS8807 is an LVDS 4K TCON with advanced scaling func ...
- 原生js实现tab切换
//通过原生js实现table切换<html><head><meta http-equiv="Content-Type" content=" ...
- UIScrollView的布局
一.UIScrollView的子控件布局不能跟其它的控件一样进行布局,因为UIScrollView会根据子控件计算出ContentSize的大小,那么我们应该如何进行布局呀. 遵循以下两点就行 1.参 ...