一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務(wù)器之家 - 編程語言 - ASP.NET教程 - ASP.NET Core 6框架揭秘實(shí)例演示[41]:跨域資源的共享(CORS)N種用法

ASP.NET Core 6框架揭秘實(shí)例演示[41]:跨域資源的共享(CORS)N種用法

2023-08-13 00:10未知服務(wù)器之家 ASP.NET教程

同源策略是所有瀏覽器都必須遵循的一項(xiàng)安全原則,它的存在決定了瀏覽器在默認(rèn)情況下無法對(duì)跨域請求的資源做進(jìn)一步處理。為了實(shí)現(xiàn)跨域資源的共享,W3C制定了CORS規(guī)范。ASP.NET利用CorsMiddleware中間件提供了針對(duì)CORS規(guī)范的實(shí)現(xiàn) 同

ASP.NET Core 6框架揭秘實(shí)例演示[41]:跨域資源的共享(CORS)N種用法同源策略是所有瀏覽器都必須遵循的一項(xiàng)安全原則,它的存在決定了瀏覽器在默認(rèn)情況下無法對(duì)跨域請求的資源做進(jìn)一步處理。為了實(shí)現(xiàn)跨域資源的共享,W3C制定了CORS規(guī)范。ASP.NET利用CorsMiddleware中間件提供了針對(duì)CORS規(guī)范的實(shí)現(xiàn)

同源策略是所有瀏覽器都必須遵循的一項(xiàng)安全原則,它的存在決定了瀏覽器在默認(rèn)情況下無法對(duì)跨域請求的資源做進(jìn)一步處理。為了實(shí)現(xiàn)跨域資源的共享,W3C制定了CORS規(guī)范。ASP.NET利用CorsMiddleware中間件提供了針對(duì)CORS規(guī)范的實(shí)現(xiàn)。(本文提供的示例演示已經(jīng)同步到《ASP.NET Core 6框架揭秘-實(shí)例演示版》)

[S2901]跨域調(diào)用API(源代碼)
[S2902]顯式指定授權(quán)Origin列表(源代碼)
[S2903]手工檢驗(yàn)指定Origin是否的權(quán)限(源代碼)
[S2904]基于策略的資源授權(quán)(匿名策略)(源代碼)
[S2905]基于策略的資源授權(quán)(具名策略)(源代碼)
[S2906]將CORS規(guī)則應(yīng)用到路由終結(jié)點(diǎn)上(代碼編程形式)(源代碼)
[S2907]將CORS規(guī)則應(yīng)用到路由終結(jié)點(diǎn)上(特性標(biāo)注形式)(源代碼)

[S2901]跨域調(diào)用API

為了方便在本機(jī)環(huán)境下模擬跨域API調(diào)用,我們通過修改Host文件將本地IP映射為多個(gè)不同的域名。我們以管理員身份打開文件“%windir%\System32\drivers\etc\hosts”,并以如下所示的方式添加了針對(duì)四個(gè)域名的映射。

127.0.0.1       www.foo.com
127.0.0.1       www.bar.com
127.0.0.1       www.baz.com
127.0.0.1       www.qux.com

我們的演示程序由圖1所示的兩個(gè)ASP.NET程序構(gòu)成。我們將API定義在Api項(xiàng)目中,App是一個(gè)JavaScript應(yīng)用程序,它會(huì)在瀏覽器環(huán)境下以跨域請求的方式調(diào)用承載于Api應(yīng)用中的API。

ASP.NET Core 6框架揭秘實(shí)例演示[41]:跨域資源的共享(CORS)N種用法

圖1 演示實(shí)例解決方案結(jié)構(gòu)

如下所示的Api程序中定義了表示聯(lián)系人的Contact記錄類型。我們注冊了針對(duì)路徑“/contacts”的路由使之以JSON的形式返回一組聯(lián)系人列表。在調(diào)用Application對(duì)象的Run方法啟動(dòng)時(shí),我們顯式指定了監(jiān)聽地址“http://0.0.0.0:8080”。

var app = Application.Create();
app.MapGet("/contacts", GetContacts);
app.Run(url:"http://0.0.0.0:8080");

static IResult GetContacts()
{
    var contacts = new Contact[]
    {
        new Contact("張三", "123", "[email protected]"),
        new Contact("李四","456", "[email protected]"),
        new Contact("王五", "789", "[email protected]")
    };
    return Results.Json(contacts);
}

public readonly record struct Contact(string Name,string PhoneNo ,string EmailAddress);

下面的代碼片段展示了App應(yīng)用程序的完整定義。我們通過注冊針對(duì)根路徑的路由使之現(xiàn)一個(gè)包含聯(lián)系人列表的Web頁面,我們在該頁面中采用jQuery以AJAX的方式調(diào)用上面這個(gè)API獲取呈現(xiàn)的聯(lián)系人列表。我們將AJAX請求的目標(biāo)地址設(shè)置為“http://www.qux.com:8080/contacts”。在AJAX請求的回調(diào)操作中,可以將返回的聯(lián)系人以無序列表的形式呈現(xiàn)出來。

var app = Application.Create();
app.MapGet("/", Render);
app.Run(url:"http://0.0.0.0:3721");

static IResult Render()
{
    var html = @"
<html>
    <body>
        <ul id='contacts'></ul>
        <script src='http://code.jquery.com/jquery-3.3.1.min.js'></script>
        <script>
        $(function()
        {
            var url = 'http://www.qux.com:8080/contacts';
            $.getJSON(url, null, function(contacts) {
                $.each(contacts, function(index, contact)
                {
                    var html = '<li><ul>';
                    html += '<li>Name: ' + contact.name + '</li>';
                    html += '<li>Phone No:' + contact.phoneNo + '</li>';
                    html += '<li>Email Address: ' + contact.emailAddress + '</li>';
                    html += '</ul>';
                    $('#contacts').append($(html));
                });
            });
        });
        </script >
    </body>
</html>";
    return Results.Text(content: html, contentType: "text/html");

然后先后啟動(dòng)應(yīng)用程序Api和App。如果利用瀏覽器采用映射的域名(www.foo.com)訪問App應(yīng)用,就會(huì)發(fā)現(xiàn)我們期待的聯(lián)系人列表并沒有呈現(xiàn)出來。如果按F12鍵查看開發(fā)工具,就會(huì)發(fā)現(xiàn)圖29-2所示的關(guān)于CORS的錯(cuò)誤,具體的錯(cuò)誤消息為“Access to XMLHttpRequest at 'http://www.qux.com:8080/contacts' from origin 'http://www.foo.com:3721' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.”。

ASP.NET Core 6框架揭秘實(shí)例演示[41]:跨域資源的共享(CORS)N種用法

圖2 跨域訪問導(dǎo)致聯(lián)系人無法呈現(xiàn)

有的讀者可能會(huì)想是否是AJAX調(diào)用發(fā)生錯(cuò)誤導(dǎo)致沒有得到聯(lián)系人信息呢。如果我們利用抓包工具捕捉AJAX請求和響應(yīng)的內(nèi)容,就會(huì)捕獲到如下所示的HTTP報(bào)文。可以看出AJAX調(diào)用其實(shí)是成功的,只是瀏覽器阻止了針對(duì)跨域請求返回?cái)?shù)據(jù)的進(jìn)一步處理。如下請求具有一個(gè)名為Origin的報(bào)頭,表示的正是AJAX請求的“源”,也就是跨域(Cross-Orgin)中的“域”。

GET http://www.qux.com:8080/contacts HTTP/1.1
Host: www.qux.com:8080
Connection: keep-alive
Accept: application/json, text/javascript, */*; q=0.01
Origin: http://www.foo.com:3721
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.67 Safari/537.36
Referer: http://www.foo.com:3721/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,zh-CN;q=0.8,zh;q=0.7
HTTP/1.1 200 OK
Date: Sat, 13 Nov 2021 11:24:58 GMT
Server: Kestrel
Content-Length: 205

[{"name":"張三","phoneNo":"123","emailAddress":"[email protected]"},{"name":"李四",
"phoneNo":"456","emailAddress":"[email protected]"},{"name":"王五","phoneNo":"789",
"emailAddress":"[email protected]"}]

[S2902]顯式指定授權(quán)Origin列表

我們可以利用注冊的CorsMiddleware中間件來解決上面這個(gè)問題。對(duì)于我們演示的實(shí)例來說,作為資源提供者的Api應(yīng)用如果希望將提供的資源授權(quán)給某個(gè)應(yīng)用程序,可以將作為資源消費(fèi)程序的“域”添加到授權(quán)域列表中。演示程序調(diào)用了UseCors擴(kuò)展方法完成了針對(duì)CorsMiddleware中間件的注冊,并指定了兩個(gè)授權(quán)的“域”。中間件涉及的服務(wù)則通過調(diào)用AddCors擴(kuò)展方法進(jìn)行注冊。

var builder = WebApplication.CreateBuilder();
builder.Services.AddCors();
var app = builder.Build();
app.UseCors(cors => cors.WithOrigins(
    "http://www.foo.com:3721",
    "http://www.bar.com:3721"));
app.MapGet("/contacts", GetContacts);
app.Run(url:"http://0.0.0.0:8080");
...

由于Api應(yīng)用對(duì)“http://www.foo.com:3721”和“http://www.bar.com:3721”這兩個(gè)域進(jìn)行了顯式授權(quán),如果采用它們來訪問App應(yīng)用程序,瀏覽器上就會(huì)呈現(xiàn)出圖3所示的聯(lián)系人列表。倘若將瀏覽器地址欄的URL設(shè)置成未被授權(quán)的“http://www.baz.com:3721”,我們依然得不到想要的顯示結(jié)果。

ASP.NET Core 6框架揭秘實(shí)例演示[41]:跨域資源的共享(CORS)N種用法

圖3 針對(duì)域的顯式授權(quán)

下面從HTTP消息交換的角度來介紹這次由Api應(yīng)用響應(yīng)的報(bào)文有何不同。如下所示的是Api針對(duì)地址為“http://www.foo.com:3721”的響應(yīng)報(bào)文,可以看出它多了兩個(gè)名稱分別為Vary和Access-Control-Allow-Origin的報(bào)頭。前者與緩存有關(guān),它要求在對(duì)響應(yīng)報(bào)文實(shí)施緩存的時(shí)候,選用的Key應(yīng)該包含請求的Origin報(bào)頭值,它提供給瀏覽器授權(quán)訪問當(dāng)前資源的域。

HTTP/1.1 200 OK
Date: Sat, 13 Nov 2021 11:24:58 GMT
Server: Kestrel
Vary: Origin
Access-Control-Allow-Origin: http://www.foo.com:3721
Content-Length: 205

[{"name":"張三","phoneNo":"123","emailAddress":"[email protected]"},{"name":"李四",
"phoneNo":"456","emailAddress":"[email protected]"},{"name":"王五","phoneNo":"789",
"emailAddress":"[email protected]"}]

[S2903]手工檢驗(yàn)指定Origin是否的權(quán)限

對(duì)于我們演示的實(shí)例來說,當(dāng)AJAX調(diào)用成功并返回聯(lián)系人列表之后,瀏覽器正是利用Access-Control-Allow-Origin報(bào)頭確定當(dāng)前請求采用的域是否有權(quán)對(duì)獲取的資源做進(jìn)一步處理的。只有在授權(quán)明確之后,瀏覽器才允許執(zhí)行將數(shù)據(jù)呈現(xiàn)出來的操作。從演示程序可以看出“跨域資源共享”所謂的“域”是由協(xié)議前綴(如“http://”或者“https://”)、主機(jī)名(或者域名)和端口號(hào)組成的,但在很多情況下,資源提供在授權(quán)的時(shí)候往往只需要考慮域名,這樣的授權(quán)策略可以采用如下所示的方式來解決。UseCors擴(kuò)展方法返回一個(gè)CorsPolicyBuilder對(duì)象,我們調(diào)用它的SetIsOriginAllowed方法利用提供的Func<string, bool>來設(shè)置授權(quán)規(guī)則,此規(guī)則只會(huì)考慮域名。

var validOrigins = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
    "www.foo.com",
    "www.bar.com"
};

var builder = WebApplication.CreateBuilder();
builder.Services.AddCors();
var app = builder.Build();
app.UseCors(cors => cors.SetIsOrigi0nAllowed(
    origin => validOrigins.Contains(new Uri(origin).Host)));
app.MapGet("/contacts", GetContacts);
app.Run(url:"http://0.0.0.0:8080");
...

[S2904]基于策略的資源授權(quán)(匿名策略)

CORS本質(zhì)上還是屬于授權(quán)的問題,所以我們采用類似于第28章“授權(quán)”介紹的方式將資源授權(quán)的規(guī)則定義成相應(yīng)的策略,CorsMiddleware中間件就可以針對(duì)某個(gè)預(yù)定義的策略來實(shí)施跨域資源授權(quán)。在調(diào)用AddCors擴(kuò)展方法時(shí)可以采用如下所示的方式注冊一個(gè)默認(rèn)的CORS策略。

var validOrigins = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
    "www.foo.com",
    "www.bar.com"
};

var builder = WebApplication.CreateBuilder();
builder.Services.AddCors(options => options.AddDefaultPolicy(policy => policy.
    SetIsOriginAllowed(origin => validOrigins.Contains(new Uri(origin).Host))));
var app = builder.Build();
app.UseCors();
app.MapGet("/contacts", GetContacts);
app.Run(url:"http://0.0.0.0:8080");
...

[S2905]基于策略的資源授權(quán)(具名策略)

除了注冊一個(gè)默認(rèn)的匿名CORS策略,我們還可以為注冊的策略命名。下面的演示程序在調(diào)用AddCors擴(kuò)展方法時(shí)注冊了一個(gè)名為“foobar”的CORS策略,在調(diào)用UseCors擴(kuò)展方法注冊CorsMiddleware中間件時(shí)就可以顯式地指定采用的策略名稱。

var validOrigins = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
    "www.foo.com",
    "www.bar.com"
};

var builder = WebApplication.CreateBuilder();
builder.Services.AddCors(options => options.AddPolicy("foobar", policy => policy.
    SetIsOriginAllowed(origin => validOrigins.Contains(new Uri(origin).Host))));
var app = builder.Build();
app.UseCors(policyName:"foobar");
app.MapGet("/contacts", GetContacts);
app.Run(url:"http://0.0.0.0:8080");
...

[S2906]將CORS規(guī)則應(yīng)用到路由終結(jié)點(diǎn)上(代碼編程形式)

除了在調(diào)用UseCors擴(kuò)展方法時(shí)指定Cors策略外,我們還可以在注冊終結(jié)點(diǎn)的時(shí)候?qū)ors規(guī)則作為路由元數(shù)據(jù)應(yīng)用到終結(jié)點(diǎn)上。如下的演示程序在調(diào)用MapGet方法注冊了針對(duì)“/contacts”路徑的終結(jié)點(diǎn)后會(huì)返回一個(gè)RouteHandlerBuilder對(duì)象,它接著調(diào)用該對(duì)象的RequireCors擴(kuò)展方法來指定采用的CORS策略名稱。

var validOrigins = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
    "www.foo.com",
    "www.bar.com"
};

var builder = WebApplication.CreateBuilder();
builder.Services.AddCors(options => options.AddPolicy("foobar", policy => policy.
    SetIsOriginAllowed(origin => validOrigins.Contains(new Uri(origin).Host))));
var app = builder.Build();
app.UseCors();
app.MapGet("/contacts", GetContacts).RequireCors(policyName:"foobar");
app.Run(url:"http://0.0.0.0:8080");
...

[S2907]將CORS規(guī)則應(yīng)用到路由終結(jié)點(diǎn)上(特性標(biāo)注形式)

我們也可以按照如下的方式在終結(jié)點(diǎn)處理方法GetContacts上標(biāo)注EnableCorsAttribute特性,并利用其“policyName”參數(shù)來指定采用的CORS策略名稱。如果使用Lambda表達(dá)式來定義終結(jié)點(diǎn)處理器,我們可以將EnableCorsAttribute特性直接標(biāo)注在Lambda表達(dá)式前面。

using Microsoft.AspNetCore.Cors;

var validOrigins = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
    "www.foo.com",
    "www.bar.com"
};

var builder = WebApplication.CreateBuilder();
builder.Services.AddCors(options => options.AddPolicy("foobar", policy => policy.
    SetIsOriginAllowed(origin => validOrigins.Contains(new Uri(origin).Host))));
var app = builder.Build();
app.UseCors();
app.MapGet("/contacts", GetContacts);
app.Run(url:"http://0.0.0.0:8080");

[EnableCors(policyName: "foobar")]
static IResult GetContacts()
{
    var contacts = new Contact[]
    {
        new Contact("張三", "123", "[email protected]"),
        new Contact("李四","456", "[email protected]"),
        new Contact("王五", "789", "[email protected]")
    };
    return Results.Json(contacts);
}
...

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 狠狠色综合久久婷婷 | 男人v天堂 | ai换脸杨颖被啪在线观看 | 亚洲成年人专区 | 日本wwxx护士 | 香蕉草莓视频 | 亚洲咪咪 | 国产欧美日韩精品在线 | 亚洲欧美国产自拍 | 草莓永久地域网名入2022 | 亚洲精品一区二区三区在线播放 | 日本一区二区三区国产 | 538亚洲欧美国产日韩在线精品 | 192.168.191 | 国内精品久久久久久中文字幕 | 密臀tv | 日本一区二区高清免费不卡 | 好湿好紧好大野战 | 拔插拔插成人 | 久久伊人精品青青草原2021 | 欧美在线观看视频一区 | 男人猛进女人屁股免费 | 99久久精品国内 | 我与恶魔的h生活ova | 亚洲AV久久无码精品九九软件 | 男人的天堂在线观看视频不卡 | 513热点 | 99热这里只有精品国产免费 | 成人福利免费视频 | 日韩二三区 | 精品在线视频一区 | 欧美大b| 白丝超短裙被输出娇喘不停小说 | 女仆掀起蕾丝裙被打屁股作文 | 国产免费视频 | 爽好紧别夹宝贝叫大声点护士 | 国产精品久久久 | 欧美视频黑鬼大战白妞 | 性xx色3d动画xx无尽 | 亚洲午夜精品久久久久久成年 | 91高清免费国产自产 |