AspNetCore源碼解析_1_CORS中間件

概述

什麼是跨域

在先後端分離開發方式中,跨域是咱們常常會遇到的問題。所謂的跨域,就是處於安全考慮,A域名向B域名發出Ajax請求,瀏覽器會拒絕,拋出相似下圖的錯誤。html

image

JSONP

JSONP不是標準跨域協議,更像是聰明程序員投機取巧的辦法。這種方式的原理就是js是沒有跨域限制的,你想一想你引用bootstrap.js是否是網絡地址放進來就能夠用了。
實際上,全部src屬性都不限制跨域的,好比img標籤使用跨域圖片是不會有問題的。nginx

過程大致分下面四步。程序員

  • 首先約定數據格式和回調函數名
  • A網站引用B網站的js
  • B網站用約定好的回調函數將數據包裹起來,在A引用的js裏返回
  • A網站在回調函數中獲取數據

這個方案的優勢是兼容性比較好,很古老的ie均可以支持,畢竟只是基於js的一個技巧,並無新的技術或協議。
缺點比較明顯,只支持GET,理解起來比較彆扭,調用失敗不會返回http狀態碼,安全性存在必定問題。json

CORS

CORS的全稱是Cross Origin Resource Sharing,翻譯過來就是跨域資源共享。bootstrap

跨域問題本質就是瀏覽器處於安全考慮,阻止了客戶端跨域請求。但說到底,客戶端請求安不安全還不是服務端說了算的,服務端都說咱們家大米大家隨便吃,瀏覽器還阻止,這不是礙事嗎,你個物業還當本身業主啦?後端

可是瀏覽器也不能隨便放行,畢竟網上衝浪的不只有正經客人,還有小偷,真出問題了還得吐槽物業稀爛。瀏覽器說,服務端,這個客戶端要去你家吃大米,你得告訴我你同不一樣意啊,服務端說我咋告訴你啊,我總不能來我的就衝着崗亭喊 I'M OK吧。瀏覽器說那咱們搞個協議吧,整個互聯網小區都按這個規範來,大家就按這個格式回覆我。設計模式

這個協議就是CORS了。跨域

graph LR; A(客戶端)-->B(不帶Orgin跨域請求); B-->C(瀏覽器拒絕); A-->D(帶Origin跨域請求); D-->E(服務端返回白名單); E-->F(白名單內); E-->G(白名單外); F-->H(瀏覽器放行); G-->C

CORS的缺點就是IE10如下不支持,若是你的項目須要兼容這些瀏覽器的話須要注意。瀏覽器

關於CORS協議詳細的內容看這篇文章安全

http://www.ruanyifeng.com/blog/2016/04/cors.html

怎麼實現CORS

CORS說白了其實就是在響應頭裏加東西,你能夠在運維環節好比nginx加,能夠在代碼里加,常見的作法是中間件統一處理。AspNetCore爲咱們提供了CORS中間件。

AspNetCore_CORS中間件的使用

使用CORS中間件兩句代碼就夠了,在Startup文件中

//注入CORS相關的服務,配置跨域策略 [CorsPolicy]
public void ConfigureServices(IServiceCollection services)
{
    //策略1,容許全部域名跨域訪問
    config.AddPolicy("policy1", policy => {
                    policy.AllowAnyOrigin().
                        AllowAnyMethod().
                        AllowAnyOrigin().
                        AllowAnyMethod();
                        //注意:AllowAnyOrigin和AllowCredential不能同時出現,不然會報錯
                        //AllowCredential便是否容許客戶端發送cookie,基於安全緣由,CORS協議規定不容許AllowOrigin爲通配符的狀況下設置容許發送cookie
                        //.AllowCredentials();
                });

    //策略2,僅容許特定域名、方法、請求頭訪問
    config.AddPolicy("policy2",policy=> {
        //只容許https://www.holdengong.com跨域訪問
        policy.WithOrigins("https://www.holdengong.com")
        //只容許get,post方法
        .WithMethods("get", "post")
        //請求頭中只容許有Authorization
        .WithHeaders("Authorization")
        //對於複雜請求,瀏覽器會首先發送預檢請求(OPTIONS),服務端返回204,並在響應頭中返回跨域設置
        //此處能夠設置預檢請求的有效時長,即30分鐘內不會再檢查是否容許跨域
        .SetPreflightMaxAge(TimeSpan.FromMinutes(30));
    });
}

//使用CORS中間件, 指定使用CorsPolicy
public void Configure(IApplicationBuilder app)
{
    app.UseCors("CorsPolicy");
}

注意:AllowAnyOrigin和AllowCredential不能同時配置,不然會報錯。若是要容許客戶端發送cookie的話,只能使用WithOrgin來執行容許跨域白名單

微軟使用的策略設計模式,方便咱們靈活使用跨域策略。好比,開發環境容許localhost跨域訪問,方便開發調試,正式環境只容許指定域名訪問。

源碼解析

核心對象

services.TryAdd(ServiceDescriptor.Transient<ICorsService, CorsService>());

services.TryAdd(ServiceDescriptor.Transient<ICorsPolicyProvider, DefaultCorsPolicyProvider>());

services.Configure(setupAction);
  • CorsOptions:主要定義了字典PolicyMap,鍵是策略名稱,值是跨域策略。用戶能夠在注入的時候往這個對象裏面加跨域策略。而後提供了一些新增策略的操做方法。
// DefaultCorsPolicyProvider returns a Task<CorsPolicy>. We'll cache the value to be returned alongside
// the actual policy instance to have a separate lookup.
internal IDictionary<string, (CorsPolicy policy, Task<CorsPolicy> policyTask)> PolicyMap { get; }
    = new Dictionary<string, (CorsPolicy, Task<CorsPolicy>)>(StringComparer.Ordinal);
  • ICorsService:有兩個方法,EvaluatePolicy--評估策略,主要作一些校驗、記錄日誌和分流預檢請求和真實請求的工做; PopulateResult--執行策略,將結果填充到CorsResult對象中。

  • ICorsPolicyProvider: 有一個方法,GetPolicyAsync--根據policyName取出跨域策略。

中間件

CorsMiddleware

首先,中間件會判斷方法節點是否有實現如下兩個接口,若是有的話優先執行節點設置。

IDisableCorsAttribute: 禁用跨域
ICorsPolicyMetadata:使用指定跨域策略

而後,而後判斷請求頭是否有Origin,沒有的話直接略過CORS中間件去下游管道。

if (!context.Request.Headers.ContainsKey(CorsConstants.Origin))
{
return _next(context);
}

而後,中間件執行ICorsService的ApplyResult方法,將跨域策略寫到響應頭中。

原文地址:holdengong.com

相關文章
相關標籤/搜索