之前的文章写了关于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的跨域签名的更多相关文章

  1. ASP.NET WebAPI解决跨域问题

    跨域是个很蛋疼的问题...随笔记录一下... 一.安装nuget包:Microsoft.AspNet.WebApi.Core 二.在Application_Start方法中启用跨域 1 protect ...

  2. 为Asp.net WebApi 添加跨域支持

    Nuget安装包:microsoft.aspnet.webapi.cors 原文地址:https://www.asp.net/web-api/overview/security/enabling-cr ...

  3. asp.net webapi支持跨域

    1.Install-Package Microsoft.AspNet.WebApi.Cors 2. using System.Web.Http; namespace WebService {     ...

  4. asp.net core webapi之跨域(Cors)访问

    这里说的跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据.只要协议.域名.端口有任何一个不同,都被当作 ...

  5. 关于WebService、WebApi的跨域问题

    随着移动互联网的发展, 传统营销模式往网站以及移动客户端转移已经成为一种趋势.接触过互联网开发的开发者肯定会很熟悉两种网络服务WebApi.WebService.在使用JavaScript进行数据交互 ...

  6. .NET压缩图片保存 .NET CORE WebApi Post跨域提交 C# Debug和release判断用法 tofixed方法 四舍五入 (function($){})(jQuery); 使用VUE+iView+.Net Core上传图片

    .NET压缩图片保存   需求: 需要将用户后买的图片批量下载打包压缩,并且分不同的文件夹(因:购买了多个用户的图片情况) 文章中用到了一个第三方的类库,Nuget下载 SharpZipLib 目前用 ...

  7. ASP.NET中Cookie跨域的问题及解决代码

    ASP.NET中Cookie跨域的问题及解决代码 http://www.liyumei.net.cn/post/share18.html Cookies揭秘  http://www.cnblogs.c ...

  8. asp.net core webapi Session 跨域

    在ajax 请求是也要加相应的东西 $.ajax({ url:url, //加上这句话 xhrFields: { withCredentials: true } success:function(re ...

  9. asp.net core webapi 配置跨域处理

    在Startup.cs文件中的ConfigureServices方法中加入如下代码: //配置跨域处理 services.AddCors(options => { options.AddPoli ...

随机推荐

  1. 多边形剪裁img

    <!DOCTYPE html><html><head> <meta charset="utf-8"/> <title>& ...

  2. spring+mybatis之声明式事务管理初识(小实例)

    前几篇的文章都只是初步学习spring和mybatis框架,所写的实例也都非常简单,所进行的数据访问控制也都很简单,没有加入事务管理.这篇文章将初步接触事务管理. 1.事务管理 理解事务管理之前,先通 ...

  3. HTTP协议(四)

    第一步:新建一个header.php页 <?php header('Location:http://www.baidu.com');//默认是302重定向 ?> 第二步:分析 如何制定重定 ...

  4. JavaScript对象的深浅复制

    前言 从层次上来看,对象的复制可以简单地分为浅复制和深复制,顾名思义,浅复制是指只复制一层对象的属性,不会复制对象中的对象的属性,对象的深复制会复制对象中层层嵌套的对象的属性. 在复制对象时,除了要复 ...

  5. Idea Maven 建本地仓库-导入本地JAR包

    需求 IDEA 很方便集成了Maven,但是也有相应的问题,比如使用Maven仓没有包的时候不太方便,这时我们需要建立自已的本地仓库来实现 实现 找到Idea的安装目录下面的Maven,我的在 C:\ ...

  6. oracle查询锁表解锁语句

    --oracle查询锁表解锁语句--首先要用dba权限的用户登录,建议用system,然后直接看sql吧 --1. 如下语句 查询锁定的表: SELECT l.session_id sid, s.se ...

  7. 持续集成:TestNG中case之间的关系

    持续集成:TestNG中case之间的关系   poptest是国内唯一一家培养测试开发工程师的培训机构,以学员能胜任自动化测试,性能测试,测试工具开发等工作为目标.如果对课程感兴趣,请大家咨询qq: ...

  8. 手机自动化测试:Appium源码之api(1)

    手机自动化测试:Appium源码之api(1)   AppiumDriver getAppStrings() 默认系统语言对应的Strings.xml文件内的数据. driver.getAppStri ...

  9. 移动开发必须要弄明白的问题】详解Eclipse转Android Studio

    2015-12-09 13:01:244264浏览3评论 AS出来一年多了,最近才从Eclipse转到AS,但我并不觉得使用Eclipse有多落后,它们都只是一个工具而已,哪个顺手就用哪个,用得好都能 ...

  10. 1.Redis 的安装

    一.Redis 介绍 Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API. 作为Key-value型数据库,Red ...