.Net Core Cors中間件的深入講解
同源策略和資源跨域共享
1、同源策略
同源策略,它是由Netscape提出的一個(gè)著名的安全策略。現(xiàn)在所有支持JavaScript 的瀏覽器都會(huì)使用這個(gè)策略。所謂同源是指,域名,協(xié)議,端口相同。
1.1、目的
主要是為了保證用戶信息的安全,防止網(wǎng)站竊取用戶數(shù)據(jù)。假如沒(méi)有同源策略,可能就會(huì)有下面這種情況的發(fā)生。用戶訪問(wèn)兩個(gè)網(wǎng)站A/B,并登錄了A網(wǎng)站,A網(wǎng)站會(huì)在計(jì)算機(jī)本地存儲(chǔ)Cookie或者Token等等,在訪問(wèn)B網(wǎng)站的時(shí)候,B網(wǎng)站就可以訪問(wèn)這些本地的存儲(chǔ)信息,B網(wǎng)站可以使用用戶的Cookie去登錄A網(wǎng)站,那這樣用戶信息就被泄露了。
1.2、限制范圍
- Cookie、LocalStorage和indexDB無(wú)法訪問(wèn)(只有同源的網(wǎng)頁(yè)才能共享Cookie)
- DOM無(wú)法獲得(父窗口和子窗口的地址是同源的才能獲取子窗口的信息)
- AJAX請(qǐng)求不能被發(fā)送(AJAX請(qǐng)求只能發(fā)送給同源的網(wǎng)址)
要知道一點(diǎn),這些限制其實(shí)都是瀏覽器做的限制。
2、跨域資源共享
跨域資源共享跟同源策略相反。在整個(gè)跨域通信過(guò)程中,瀏覽器會(huì)自動(dòng)識(shí)別此次請(qǐng)求是否跨域,一旦發(fā)現(xiàn)跨域,就自動(dòng)添加請(qǐng)求頭信息(如Origin)或者自動(dòng)發(fā)送一次請(qǐng)求方式為option的預(yù)請(qǐng)求。瀏覽器將CORS請(qǐng)求分為兩類:簡(jiǎn)單請(qǐng)求和非簡(jiǎn)單請(qǐng)求。
2.1、簡(jiǎn)單請(qǐng)求
當(dāng)瀏覽器的請(qǐng)求方式是Head、Get或者Post,并且HTTP的頭信息中不會(huì)超出以下字段:
- Accept
- Accept-Language
- Content-Language
- Origin
時(shí),瀏覽器會(huì)將該請(qǐng)求定義為簡(jiǎn)單請(qǐng)求,否則就是非簡(jiǎn)單請(qǐng)求。當(dāng)瀏覽器判斷為簡(jiǎn)單請(qǐng)求后,瀏覽器會(huì)自動(dòng)再請(qǐng)求報(bào)文頭中加上Origin字段,表明此次請(qǐng)求來(lái)自的地址(協(xié)議+域名+端口)。然后服務(wù)器需要去判斷是否接受這個(gè)來(lái)源的請(qǐng)求。如果允許服務(wù)器端返回的頭部中需要有Access-Control-Allow-Origin,其值為請(qǐng)求時(shí)Origin字段的值或*(表示接受任意源的請(qǐng)求)。請(qǐng)求頭中還會(huì)有Access-Control-Allow-Methods表示服務(wù)器允許的跨域請(qǐng)求的方式。Access-Control-Allow-Headers表示請(qǐng)求頭中允許出現(xiàn)的字段。
2.2、 非簡(jiǎn)單請(qǐng)求
當(dāng)瀏覽器判斷為非簡(jiǎn)單請(qǐng)求后,會(huì)發(fā)送兩次請(qǐng)求,首先瀏覽器會(huì)自動(dòng)發(fā)送一個(gè)請(qǐng)求方式為options的請(qǐng)求,并在請(qǐng)求頭中
- 加上Access-Control-Request-Method表示下次請(qǐng)求的方法,
- 加上Origin表明來(lái)源,
- 加上Access-Control-Request-Headers表示下次請(qǐng)求的請(qǐng)求頭中額外的字段。
服務(wù)器收到請(qǐng)求后,需要獲取這三個(gè)請(qǐng)求頭中的值,并進(jìn)行判斷,確認(rèn)是否允許進(jìn)行跨域。如果服務(wù)器返回的請(qǐng)求頭中沒(méi)有任何CORS相關(guān)的請(qǐng)求頭信息,瀏覽器會(huì)認(rèn)為不通過(guò)預(yù)檢,也不會(huì)進(jìn)行第二次請(qǐng)求。
服務(wù)器如果接受跨域并驗(yàn)證通過(guò)了options的請(qǐng)求,會(huì)返回Access-Control-Allow-Origin(表明允許跨域請(qǐng)求的源)、Access-Control-Allow-Methods(允許跨域請(qǐng)求的請(qǐng)求方式)、Access-Control-Allow-Headers(允許請(qǐng)求頭中包含的額外字段)。然后瀏覽器才會(huì)發(fā)送真正的請(qǐng)求。
(第一次options請(qǐng)求)
(第二次請(qǐng)求)
二、服務(wù)端實(shí)現(xiàn)CORS
在.Net Core Web Api中使用很簡(jiǎn)單,首先安裝包Microsoft.AspNet.WebApi.Cors
,在StartUp中添加下面兩句
public void ConfigureServices(IServiceCollection services) { services.AddMvc(); //添加Cors,并配置CorsPolicy services.AddCors(options => options.AddPolicy("CorsTest", p => p.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod())); } public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } //注意UseCors()要在UseMvc()之前 app.UseCors("CorsTest"); app.UseMvc(); }
在使用的時(shí)候只需要在Controller或者Action中加上特性[EnableCors("CorsTest")]
[EnableCors("CorsTest")] public class ValuesController : Controller { private ILogger<ValuesController> _logger; public ValuesController(ILogger<ValuesController> logger) { _logger = logger; } [HttpGet] public IEnumerable<string> Get() { return new string[] { "value1", "value2" }; } }
現(xiàn)在服務(wù)端已經(jīng)配置好了,現(xiàn)在需要通過(guò)前端跨域請(qǐng)求
<html> <head> 測(cè)試 </head> <body> 測(cè)試 </body> </html> <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script> <script type="text/javascript"> $(function () { $.ajax({ type: "get", url: "http://localhost:7000/api/values", beforeSend: function (request) {//在請(qǐng)求報(bào)文頭中加入Authorization 目的是讓請(qǐng)求為非簡(jiǎn)單請(qǐng)求 request.setRequestHeader("Authorization", "Bearer 071899A00D4D4C5B1C41A6B0211B9399"); }, success: function (result) { alert(result); } }, "json"); }); </script>
測(cè)試結(jié)果如下圖:
(options請(qǐng)求)
(第二次請(qǐng)求)
上面配置允許所有的地址請(qǐng)求這個(gè)接口,也可以單獨(dú)配置某個(gè)地址。
services.AddCors(options => options.AddPolicy("CorsTest", p => p.WithOrigins("http://localhost:8089") .AllowAnyHeader() .AllowAnyMethod()));
三、解析Cors源碼
打開(kāi)CORS源碼,主要的是CorsMiddleware、CorsOptions、CorsPolicy、CorsPolicyBuilder、CorsResult、CorsService這幾個(gè)類。
- CorsPolicy:就是我們?cè)赟tartup中的配置,如允許哪些域名可以跨域請(qǐng)求,允許哪些跨域請(qǐng)求方式,允許哪些額外的請(qǐng)求頭,每個(gè)配置對(duì)應(yīng)一個(gè)名稱。
services.AddCors(options => options.AddPolicy("CorsTest", p => p.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()));
- CorsOptions:中包含一個(gè)字典
IDictionary<string, CorsPolicy> PolicyMap
,一個(gè)項(xiàng)目可能有過(guò)個(gè)Cors配置,所以這個(gè)CorsOptions就是通過(guò)配置名稱管理這些配置的。 - CorsPolicyBuilder:通過(guò)它來(lái)構(gòu)造CorsPolicy。
- CorsResult:是驗(yàn)證跨域過(guò)程得到的結(jié)果。如在第一次Options請(qǐng)求時(shí),客戶端發(fā)送了Origi:http://localhost:8089,服務(wù)器會(huì)返回Access-Control-Allow-Origin:http://localhost:8089,服務(wù)器驗(yàn)證http://localhost:8089這個(gè)域名是否允許跨域,如果允許就將“http://localhost:8089”這個(gè)值存儲(chǔ)到CorsResult的AllowedHeaders中,在請(qǐng)求(第一次請(qǐng)求)返回的時(shí)候?qū)⑦@些加到HTTP請(qǐng)求頭中。
- CorsMiddleware:Cors中間件類,主要方法就是Invoke,每次HTTP請(qǐng)求都會(huì)調(diào)用這個(gè)方法。
public async Task Invoke(HttpContext context) {//判斷HTTP請(qǐng)求頭是否有Origin,由此判斷是不是跨域請(qǐng)求 if (context.Request.Headers.ContainsKey(CorsConstants.Origin)) { var corsPolicy = _policy ?? await _corsPolicyProvider?.GetPolicyAsync(context, _corsPolicyName); if (corsPolicy != null) { var accessControlRequestMethod = context.Request.Headers[CorsConstants.AccessControlRequestMethod]; //如果是跨域請(qǐng)求 判斷是不是第一次Options請(qǐng)求 if (string.Equals(context.Request.Method,CorsConstants.PreflightHttpMethod,StringComparison.OrdinalIgnoreCase) &&!StringValues.IsNullOrEmpty(accessControlRequestMethod)) { //判斷是否允許當(dāng)前請(qǐng)求跨域,根據(jù)HttpContext的內(nèi)容和Cors配置 得到CorsResult,然后將CorsResult的內(nèi)容添加到請(qǐng)求頭中(看下面詳細(xì)解釋) ApplyCorsHeaders(context, corsPolicy); context.Response.StatusCode = StatusCodes.Status204NoContent; return; } else {// 執(zhí)行第二次非Options請(qǐng)求 context.Response.OnStarting(state => { var (httpContext, policy) = (Tuple<HttpContext, CorsPolicy>)state; try { ApplyCorsHeaders(httpContext, policy); } catch (Exception exception) { _logger.FailedToSetCorsHeaders(exception); } return Task.CompletedTask; }, Tuple.Create(context, corsPolicy)); } } } await _next(context); } private void ApplyCorsHeaders(HttpContext context, CorsPolicy corsPolicy) { //通過(guò)HTTP上下文請(qǐng)求的數(shù)據(jù)和Cors配置 得到CorsResult 如在第一次Options請(qǐng)求時(shí),客戶端發(fā)送了Origi:http://localhost:8089,Access-Control-Resquest-Methods:GET 服務(wù)器會(huì)返回Access-Control-Allow-Origin:http://localhost:8089,Access-Control-Allow-Methods:GET 服務(wù)器驗(yàn)證http://localhost:8089這個(gè)域名以GET請(qǐng)求方式是否允許跨域, 如果允許就將“http://localhost:8089”這個(gè)值存儲(chǔ)到CorsResult的AllowedHeaders中 將"GET"存儲(chǔ)到CorsResult的AllowedMethods中 var corsResult = _corsService.EvaluatePolicy(context, corsPolicy); //將CorsResult中的值添加到相應(yīng)頭中的,返回到客戶端 _corsService.ApplyResult(corsResult, context.Response); }
相對(duì)來(lái)說(shuō)Cors源碼還是比較簡(jiǎn)單的,很容易看懂。可以自己寫(xiě)一個(gè)項(xiàng)目,然后掛上源碼單步調(diào)試。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
ASP.NET生成eurl.axd Http異常錯(cuò)誤的處理方法
在IIS6中同時(shí)啟用了ASP.NET 2.0 和 ASP.NET 4.0 后,網(wǎng)站程序可能會(huì)出現(xiàn)如下錯(cuò)誤:“ System.Web.HttpException: Path ‘//eurl.axd/‘ was not found. ”2011-05-05ASP.NET MVC擴(kuò)展HtmlHelper方法
這篇文章介紹了ASP.NET MVC擴(kuò)展HtmlHelper的方法,文中通過(guò)示例代碼介紹的非常詳細(xì)。對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-03-03用WPF實(shí)現(xiàn)屏幕文字提示的實(shí)現(xiàn)方法
本文介紹WPF應(yīng)用程序?qū)崿F(xiàn)在屏幕上顯示一行或多行文字通知。它沒(méi)有標(biāo)題欄和最大化最小化等按鈕,可以有半透明背景以使文字的顯示更清晰,鼠標(biāo)點(diǎn)擊后提示消失。2013-07-07asp.net與Discuz!NT整合集成實(shí)例教程
由于項(xiàng)目需要一個(gè)論壇,本來(lái)有CS的,在.net下很出名的國(guó)外開(kāi)源論壇。但為了適應(yīng)國(guó)內(nèi)的風(fēng)氣,最后選用在國(guó)內(nèi)如日中天的Discuz!NT。將Discuz與asp.net開(kāi)發(fā)的網(wǎng)站整合,有很多人已經(jīng)完成了。2009-11-11擴(kuò)展方法ToJSON() and ParseJSON()
AJAX編程經(jīng)常需要Object<=>JSON之間轉(zhuǎn)換,寫(xiě)了二個(gè)擴(kuò)展方法: public static string ToJSON(this object obj) public static T ParseJSON<T>(this string str)2008-03-03asp.net core3.1cookie和jwt混合認(rèn)證授權(quán)實(shí)現(xiàn)多種身份驗(yàn)證方案
身份驗(yàn)證是確定用戶身份的過(guò)程。 授權(quán)是確定用戶是否有權(quán)訪問(wèn)資源的過(guò)程。本文主要介紹了asp.net core3.1cookie和jwt混合認(rèn)證授權(quán)實(shí)現(xiàn)多種身份驗(yàn)證方案,感興趣的可以了解一下2021-09-09asp.net core webapi文件上傳功能的實(shí)現(xiàn)
這篇文章主要介紹了asp.net core webapi文件上傳功能的實(shí)現(xiàn),本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12得到真實(shí)外網(wǎng)IP、IP所在國(guó)家、省份、地區(qū)(小偷程序)
通過(guò)正則抓取IP顯示網(wǎng)站中的數(shù)據(jù),并篩選出所需要的內(nèi)容即可。2011-11-11