简析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 ...
随机推荐
- 技术方案:在外部网址调试本地js(基于fiddler)
1 解决的问题 1) 场景1:生产环境报错 对前台开发来说,业务逻辑都在js中,所以报错90%以上都是js问题. 如果生产环境出现报错,但是测试环境正常.这时修改了代码没有环境验证效果, ...
- ICC_lab总结——ICC_lab2:设计规划
PS:字丑,禁止转载!!! 首先先写出大概的流程,然后是一些教材的理论知识总结,最后是进行lab2的一些流程概述. 教材的理论知识总结主要是:数字集成电路物理设计学习总结--布图规划和布局 --> ...
- WinFrom中使用WPF的窗体
步骤 1.添加WindowsFormsIntegration.dll .System.Windows.Forms.和System.Xaml,PresentationCore.PresentationF ...
- iOS开发之判断横竖屏切换
/** * 当屏幕即将旋转的时候调用 * * @param toInterfaceOrientation 旋转完毕后的最终方向 * @param duration 旋转动画所花费的时间 */ ...
- artemplate使用
最近写了一个菜谱展示的网页,其中用到了artemplate模板,关于artemplate的好处就不多说了,直接上干货 1. <script src="js/template-nativ ...
- HDU-2298 Toxophily (三分法入门系列)
题意: 意大利炮射出炮弹的速度为v,求在(0,0)击中(x,y)处的目标,发射炮弹的角度. 题解: 设f(α)表示角度为α时, f(α) = vsin(α) * t - 4.9 * t * t ① ...
- JavaWeb总结(三)—JSP
一.JSP简介 1.基本认识 (1)JSP页面是由HTML语句和嵌套在其中的Java代码组成的一个普通文本文件,JSP 页面的文件扩展名必须为.jsp. (2)在JSP页面中编写的Java代码需要嵌套 ...
- 设计模式的征途—2.简单工厂(Simple Factory)模式
工厂模式是最常用的一种创建型模式,通常所说的工厂模式一般是指工厂方法模式.本篇是是工厂方法模式的“小弟”,我们可以将其理解为工厂方法模式的预备知识,它不属于GoF 23种设计模式,但在软件开发中却也应 ...
- SIM9001GSM模块教程
博主最近在做一个项目,用到了GSM模块,博主不是什么单片机大神,只是感觉某宝附带的资料太水,所以上传一些自己写的程序和经验,供需要的人参考 1,拨打电话 /********************** ...
- js的apply()与call()的区别
1.各自对应的不同的语法: /*apply()方法*/ function.apply(thisObj[, argArray]) /*call()方法*/ function.call(thisObj[, ...