Włączanie żądań między źródłami (CORS) w usłudze ASP.NET Core
Uwaga
Nie jest to najnowsza wersja tego artykułu. Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.
Ważne
Te informacje odnoszą się do produktu w wersji wstępnej, który może zostać znacząco zmodyfikowany, zanim zostanie wydany komercyjnie. Firma Microsoft nie udziela żadnych gwarancji, jawnych lub domniemanych, w odniesieniu do informacji podanych w tym miejscu.
Aby zapoznać się z bieżącą wersją, zobacz wersję tego artykułu platformy .NET 9.
Autorzy: Rick Anderson i Kirk Larkin
W tym artykule pokazano, jak rozszerzenie Cross-O rigin Resource Sharing (CORS) jest włączone w aplikacji ASP.NET Core.
Zabezpieczenia przeglądarki uniemożliwiają stronie internetowej wykonywanie żądań do innej domeny niż ta, która obsłużyła stronę internetową. To ograniczenie określa się jako zasadę tego samego źródła. Zasada tego samego źródła uniemożliwia złośliwym witrynom odczytywanie poufnych danych z innej witryny. Czasami możesz zezwolić innym witrynom na wykonywanie żądań w aplikacji o innym źródle. Aby uzyskać więcej informacji, zobacz artykuł Mozilla CORS.
Współużytkowanie zasobów między źródłami (CORS):
- Jest standardem W3C, który umożliwia serwerowi złagodzenie zasad tego samego źródła.
- Nie jest funkcją zabezpieczeń, mechanizm CORS zrelaksuje zabezpieczenia. Interfejs API nie jest bezpieczniejszy, zezwalając na mechanizm CORS. Aby uzyskać więcej informacji, zobacz Jak działa mechanizm CORS.
- Zezwala serwerowi na jawne zezwalanie na niektóre żądania między źródłami podczas odrzucania innych.
- Jest bezpieczniejszy i bardziej elastyczny niż wcześniejsze techniki, takie jak JSONP.
Wyświetl lub pobierz przykładowy kod (jak pobrać)
To samo źródło
Dwa adresy URL mają to samo źródło, jeśli mają identyczne schematy, hosty i porty (RFC 6454).
Te dwa adresy URL mają to samo źródło:
https://example.com/foo.html
https://example.com/bar.html
Te adresy URL mają inne źródła niż poprzednie dwa adresy URL:
https://example.net
: Inna domenahttps://contoso.example.com/foo.html
: Inna poddomenahttp://example.com/foo.html
: Inny schemathttps://example.com:9000/foo.html
: Inny port
Włączanie mechanizmu CORS
Istnieją trzy sposoby włączania mechanizmu CORS:
- W przypadku oprogramowania pośredniczącego przy użyciu nazwanych zasad lub zasad domyślnych.
- Korzystanie z routingu punktów końcowych.
- Za pomocą atrybutu [EnableCors].
Użycie atrybutu [EnableCors] z nazwanymi zasadami zapewnia najlepszą kontrolę w ograniczaniu punktów końcowych obsługujących mechanizm CORS.
Ostrzeżenie
UseCors musi być wywoływana w odpowiedniej kolejności. Aby uzyskać więcej informacji, zobacz Kolejność oprogramowania pośredniczącego. Na przykład UseCors
należy wywołać metodę przed UseResponseCaching użyciem polecenia UseResponseCaching
.
Każde podejście zostało szczegółowo opisane w poniższych sekcjach.
MECHANIZM CORS z nazwanymi zasadami i oprogramowaniem pośredniczącym
Oprogramowanie pośredniczące CORS obsługuje żądania między źródłami. Poniższy kod stosuje zasady CORS do wszystkich punktów końcowych aplikacji z określonymi źródłami:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
// services.AddResponseCaching();
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.MapControllers();
app.Run();
Powyższy kod ma następujące działanie:
- Ustawia nazwę zasad na
_myAllowSpecificOrigins
. Nazwa zasad jest dowolna. - Wywołuje metodę UseCors rozszerzenia i określa
_myAllowSpecificOrigins
zasady CORS.UseCors
dodaje oprogramowanie pośredniczące CORS. WywołanieUseCors
musi zostać umieszczone poUseRouting
metodzie , ale przedUseAuthorization
. Aby uzyskać więcej informacji, zobacz Kolejność oprogramowania pośredniczącego. - Wywołania AddCors za pomocą wyrażenia lambda. Lambda przyjmuje CorsPolicyBuilder obiekt. Opcje konfiguracji, takie jak
WithOrigins
, zostały opisane w dalszej części tego artykułu. _myAllowSpecificOrigins
Włącza zasady CORS dla wszystkich punktów końcowych kontrolera. Zobacz Routing punktów końcowych, aby zastosować zasady CORS do określonych punktów końcowych.- W przypadku korzystania z oprogramowania pośredniczącego buforowania odpowiedzi wywołaj metodę UseCors przed UseResponseCaching.
W przypadku routingu punktów końcowych oprogramowanie pośredniczące CORS musi być skonfigurowane do wykonywania między wywołaniami do UseRouting
i UseEndpoints
.
Wywołanie AddCors metody dodaje usługi CORS do kontenera usługi aplikacji:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
// services.AddResponseCaching();
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.MapControllers();
app.Run();
Aby uzyskać więcej informacji, zobacz opcje zasad MECHANIZMU CORS w tym dokumencie.
CorsPolicyBuilder Metody można połączyć łańcuchem, jak pokazano w poniższym kodzie:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.MapControllers();
app.Run();
Uwaga: określony adres URL nie może zawierać ukośnika końcowego (/
). Jeśli adres URL zakończy się ciągiem /
, porównanie zwróci wartość false
i nie zostanie zwrócony żaden nagłówek.
Kolejność składników UseCors i UseStaticFiles
UseStaticFiles
Zazwyczaj jest wywoływana przed UseCors
. Aplikacje korzystające z języka JavaScript do pobierania plików statycznych między witrynami muszą wywoływać przed UseStaticFiles
.UseCors
MECHANIZM CORS z domyślnymi zasadami i oprogramowaniem pośredniczącym
Poniższy wyróżniony kod włącza domyślne zasady MECHANIZMU CORS:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.Run();
Powyższy kod stosuje domyślne zasady CORS do wszystkich punktów końcowych kontrolera.
Włączanie mechanizmu Cors z routingiem punktów końcowych
W przypadku routingu punktu końcowego mechanizm CORS można włączyć dla poszczególnych punktów końcowych przy użyciu RequireCors zestawu metod rozszerzeń:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/echo",
context => context.Response.WriteAsync("echo"))
.RequireCors(MyAllowSpecificOrigins);
endpoints.MapControllers()
.RequireCors(MyAllowSpecificOrigins);
endpoints.MapGet("/echo2",
context => context.Response.WriteAsync("echo2"));
endpoints.MapRazorPages();
});
app.Run();
Powyższy kod:
app.UseCors
włącza oprogramowanie pośredniczące CORS. Ponieważ nie skonfigurowano zasad domyślnych,app.UseCors()
sam nie włącza mechanizmu CORS.- Punkty
/echo
końcowe kontrolera i zezwalają na żądania między źródłami przy użyciu określonych zasad. - Punkty
/echo2
końcowe stron i Razor nie zezwalają na żądania między źródłami, ponieważ nie określono żadnych domyślnych zasad.
Atrybut [DisableCors] nie wyłącza mechanizmu CORS, który został włączony przez routing punktu końcowego za pomocą polecenia RequireCors
.
Zobacz Testowanie mechanizmu CORS za pomocą atrybutu [EnableCors] i metody RequireCors, aby uzyskać instrukcje dotyczące testowania kodu podobnego do poprzedniego.
Włączanie mechanizmu CORS z atrybutami
Włączenie mechanizmu CORS za pomocą atrybutu [EnableCors] i zastosowanie nazwanych zasad tylko do tych punktów końcowych, które wymagają mechanizmu CORS, zapewnia najlepszą kontrolę.
Atrybut [EnableCors] zapewnia alternatywę dla stosowania mechanizmu CORS globalnie. Atrybut [EnableCors]
umożliwia mechanizm CORS dla wybranych punktów końcowych, a nie wszystkich punktów końcowych:
[EnableCors]
określa zasady domyślne.[EnableCors("{Policy String}")]
określa nazwane zasady.
Atrybut [EnableCors]
można zastosować do:
- Razor Strona
PageModel
- Kontroler
- Metoda akcji kontrolera
Różne zasady można stosować do kontrolerów, modeli stron lub metod akcji za pomocą atrybutu [EnableCors]
. [EnableCors]
Gdy atrybut jest stosowany do kontrolera, modelu strony lub metody akcji, a mechanizm CORS jest włączony w programie pośredniczącym, stosowane są obie zasady. Zalecamy łączenie zasad. Użyj przycisku[EnableCors]
atrybutu lub oprogramowania pośredniczącego, a nie obu w tej samej aplikacji.
Poniższy kod stosuje inne zasady do każdej metody:
[Route("api/[controller]")]
[ApiController]
public class WidgetController : ControllerBase
{
// GET api/values
[EnableCors("AnotherPolicy")]
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "green widget", "red widget" };
}
// GET api/values/5
[EnableCors("Policy1")]
[HttpGet("{id}")]
public ActionResult<string> Get(int id)
{
return id switch
{
1 => "green widget",
2 => "red widget",
_ => NotFound(),
};
}
}
Poniższy kod tworzy dwie zasady CORS:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("Policy1",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
options.AddPolicy("AnotherPolicy",
policy =>
{
policy.WithOrigins("http://www.contoso.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.Run();
Aby uzyskać najlepszą kontrolę nad ograniczaniem żądań CORS:
- Użyj
[EnableCors("MyPolicy")]
z nazwanymi zasadami. - Nie należy definiować zasad domyślnych.
- Nie używaj routingu punktów końcowych.
Kod w następnej sekcji spełnia poprzednią listę.
Wyłączanie mechanizmu CORS
Atrybut [DisableCors] nie wyłącza mechanizmu CORS, który został włączony przez routing punktu końcowego.
Poniższy kod definiuje zasady "MyPolicy"
MECHANIZMU CORS:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "MyPolicy",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com")
.WithMethods("PUT", "DELETE", "GET");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints => {
endpoints.MapControllers();
endpoints.MapRazorPages();
});
app.Run();
Poniższy kod wyłącza mechanizm CORS dla GetValues2
akcji:
[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public IActionResult Get() =>
ControllerContext.MyDisplayRouteInfo();
// GET api/values/5
[HttpGet("{id}")]
public IActionResult Get(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// PUT api/values/5
[HttpPut("{id}")]
public IActionResult Put(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// GET: api/values/GetValues2
[DisableCors]
[HttpGet("{action}")]
public IActionResult GetValues2() =>
ControllerContext.MyDisplayRouteInfo();
}
Powyższy kod ma następujące działanie:
- Nie włącza mechanizmu CORS z routingiem punktów końcowych.
- Nie definiuje domyślnych zasad CORS.
- Używa funkcji [EnableCors("MyPolicy")] w celu włączenia
"MyPolicy"
zasad CORS dla kontrolera. - Wyłącza mechanizm CORS dla
GetValues2
metody .
Aby uzyskać instrukcje dotyczące testowania poprzedniego kodu, zobacz Testowanie mechanizmu CORS .
Opcje zasad MECHANIZMU CORS
W tej sekcji opisano różne opcje, które można ustawić w zasadach MECHANIZMU CORS:
- Ustawianie dozwolonych źródeł
- Ustawianie dozwolonych metod HTTP
- Ustawianie dozwolonych nagłówków żądań
- Ustawianie uwidocznionych nagłówków odpowiedzi
- Poświadczenia w żądaniach między źródłami
- Ustawianie czasu wygaśnięcia przedlotu
AddPolicy jest wywoływana w pliku Program.cs
. W przypadku niektórych opcji warto zapoznać się z sekcją Jak działa mechanizm CORS.
Ustawianie dozwolonych źródeł
AllowAnyOrigin: zezwala na żądania CORS ze wszystkich źródeł przy użyciu dowolnego schematu (http
lub https
). AllowAnyOrigin
jest niezabezpieczona, ponieważ każda witryna internetowa może wysyłać żądania między źródłami do aplikacji.
Uwaga
Określanie AllowAnyOrigin
i AllowCredentials
jest niezabezpieczoną konfiguracją i może spowodować fałszerzowanie żądań między witrynami. Usługa CORS zwraca nieprawidłową odpowiedź CORS, gdy aplikacja jest skonfigurowana przy użyciu obu metod.
AllowAnyOrigin
dotyczy żądań wstępnych i nagłówka Access-Control-Allow-Origin
. Aby uzyskać więcej informacji, zobacz sekcję Wstępne żądania .
SetIsOriginAllowedToAllowWildcardSubdomains: Ustawia IsOriginAllowed właściwość zasad jako funkcję, która umożliwia źródłom dopasowanie skonfigurowanej domeny wieloznacznych podczas oceny, czy źródło jest dozwolone.
var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("https://*.example.com")
.SetIsOriginAllowedToAllowWildcardSubdomains();
});
});
builder.Services.AddControllers();
var app = builder.Build();
Ustawianie dozwolonych metod HTTP
- Zezwala na dowolną metodę HTTP:
- Wpływa na żądania wstępne i
Access-Control-Allow-Methods
nagłówek. Aby uzyskać więcej informacji, zobacz sekcję Wstępne żądania .
Ustawianie dozwolonych nagłówków żądań
Aby zezwolić na wysyłanie określonych nagłówków w żądaniu CORS, nazywanym nagłówkami żądań autora, wywołaj WithHeaders i określ dozwolone nagłówki:
using Microsoft.Net.Http.Headers;
var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com")
.WithHeaders(HeaderNames.ContentType, "x-custom-header");
});
});
builder.Services.AddControllers();
var app = builder.Build();
Aby zezwolić na wszystkie nagłówki żądań autora, wywołaj metodę AllowAnyHeader:
var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("https://*.example.com")
.AllowAnyHeader();
});
});
builder.Services.AddControllers();
var app = builder.Build();
AllowAnyHeader
dotyczy żądań wstępnych i nagłówka Access-Control-Request-Headers . Aby uzyskać więcej informacji, zobacz sekcję Wstępne żądania .
Zasady oprogramowania pośredniczącego CORS są zgodne z określonymi nagłówkami określonymi przez WithHeaders
usługę jest możliwe tylko wtedy, gdy nagłówki wysyłane w Access-Control-Request-Headers
formacie dokładnie odpowiadają nagłówkom określonym w elemencie WithHeaders
.
Rozważmy na przykład aplikację skonfigurowaną w następujący sposób:
app.UseCors(policy => policy.WithHeaders(HeaderNames.CacheControl));
Oprogramowanie pośredniczące CORS odrzuca żądanie wstępne z następującym nagłówkiem żądania, ponieważ Content-Language
(HeaderNames.ContentLanguage) nie ma na liście :WithHeaders
Access-Control-Request-Headers: Cache-Control, Content-Language
Aplikacja zwraca odpowiedź 200 OK , ale nie wysyła nagłówków CORS z powrotem. W związku z tym przeglądarka nie podejmuje próby żądania między źródłami.
Ustawianie uwidocznionych nagłówków odpowiedzi
Domyślnie przeglądarka nie ujawnia wszystkich nagłówków odpowiedzi aplikacji. Aby uzyskać więcej informacji, zobacz Udostępnianie zasobów między źródłami W3C (terminologia): prosty nagłówek odpowiedzi.
Nagłówki odpowiedzi, które są dostępne domyślnie, to:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
Specyfikacja MECHANIZMU CORS wywołuje te nagłówki prostych nagłówków odpowiedzi. Aby udostępnić inne nagłówki aplikacji, wywołaj metodę WithExposedHeaders:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyExposeResponseHeadersPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.WithExposedHeaders("x-custom-header");
});
});
builder.Services.AddControllers();
var app = builder.Build();
Poświadczenia w żądaniach między źródłami
Poświadczenia wymagają specjalnej obsługi w żądaniu CORS. Domyślnie przeglądarka nie wysyła poświadczeń z żądaniem między źródłami. Poświadczenia obejmują pliki cookie i schematy uwierzytelniania HTTP. Aby wysyłać poświadczenia z żądaniem między źródłami, klient musi ustawić wartość XMLHttpRequest.withCredentials
true
.
Bezpośrednie użycie XMLHttpRequest
:
var xhr = new XMLHttpRequest();
xhr.open('get', 'https://www.example.com/api/test');
xhr.withCredentials = true;
Korzystanie z zapytania jQuery:
$.ajax({
type: 'get',
url: 'https://www.example.com/api/test',
xhrFields: {
withCredentials: true
}
});
Korzystanie z interfejsu API pobierania:
fetch('https://www.example.com/api/test', {
credentials: 'include'
});
Serwer musi zezwalać na poświadczenia. Aby zezwolić na poświadczenia między źródłami, wywołaj metodę AllowCredentials:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyMyAllowCredentialsPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.AllowCredentials();
});
});
builder.Services.AddControllers();
var app = builder.Build();
Odpowiedź HTTP zawiera Access-Control-Allow-Credentials
nagłówek, który informuje przeglądarkę, że serwer zezwala na poświadczenia dla żądania między źródłami.
Jeśli przeglądarka wysyła poświadczenia, ale odpowiedź nie zawiera prawidłowego Access-Control-Allow-Credentials
nagłówka, przeglądarka nie uwidacznia odpowiedzi na aplikację, a żądanie między źródłami zakończy się niepowodzeniem.
Zezwolenie na poświadczenia między źródłami jest zagrożeniem bezpieczeństwa. Witryna internetowa w innej domenie może wysyłać poświadczenia zalogowanego użytkownika do aplikacji w imieniu użytkownika bez wiedzy użytkownika.
Specyfikacja MECHANIZMU CORS stwierdza również, że ustawienie wartości origins na "*"
(wszystkie źródła) jest nieprawidłowe, jeśli Access-Control-Allow-Credentials
nagłówek jest obecny.
Żądania wstępne
W przypadku niektórych żądań CORS przeglądarka wysyła dodatkowe żądanie OPTIONS przed wysłaniem rzeczywistego żądania. To żądanie jest nazywane żądaniem wstępnym. Przeglądarka może pominąć żądanie wstępne, jeśli spełnione są wszystkie następujące warunki:
- Metoda żądania to GET, HEAD lub POST.
- Aplikacja nie ustawia nagłówków żądań innych niż
Accept
, ,Accept-Language
,Content-Language
,Content-Type
lubLast-Event-ID
. - Nagłówek
Content-Type
, jeśli jest ustawiony, ma jedną z następujących wartości:application/x-www-form-urlencoded
multipart/form-data
text/plain
Reguła nagłówków żądań ustawiona dla żądania klienta ma zastosowanie do nagłówków ustawianych przez aplikację przez wywołanie setRequestHeader
XMLHttpRequest
obiektu. Specyfikacja MECHANIZMU CORS wywołuje te nagłówki żądań autora. Reguła nie ma zastosowania do nagłówków, które można ustawić w przeglądarce, takich jak User-Agent
, Host
lub Content-Length
.
Uwaga
Ten artykuł zawiera adresy URL utworzone przez wdrożenie przykładowego kodu w dwóch witrynach internetowych platformy Azure i https://cors3.azurewebsites.net
https://cors.azurewebsites.net
.
Poniżej przedstawiono przykładową odpowiedź podobną do żądania wstępnego wykonanego z przycisku [Put test] w sekcji Test CORS tego dokumentu.
General:
Request URL: https://cors3.azurewebsites.net/api/values/5
Request Method: OPTIONS
Status Code: 204 No Content
Response Headers:
Access-Control-Allow-Methods: PUT,DELETE,GET
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f8...8;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Vary: Origin
Request Headers:
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Method: PUT
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0
Żądanie wstępne używa metody HTTP OPTIONS . Może zawierać następujące nagłówki:
- Access-Control-Request-Method: metoda HTTP, która będzie używana dla rzeczywistego żądania.
- Access-Control-Request-Headers: lista nagłówków żądań ustawianych przez aplikację w rzeczywistym żądaniu. Jak wspomniano wcześniej, nie zawiera to nagłówków ustawionych przez przeglądarkę, takich jak
User-Agent
.
Jeśli żądanie wstępne zostanie odrzucone, aplikacja zwróci 200 OK
odpowiedź, ale nie ustawi nagłówków CORS. W związku z tym przeglądarka nie podejmuje próby żądania między źródłami. Aby zapoznać się z przykładem odmowy żądania wstępnego, zobacz sekcję Test CORS tego dokumentu.
Za pomocą narzędzi F12 aplikacja konsolowa wyświetla błąd podobny do jednego z następujących, w zależności od przeglądarki:
- Firefox: Żądanie między źródłami zablokowane: Te same zasady pochodzenia nie zezwalają na odczytywanie zasobu zdalnego pod adresem
https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5
. (Przyczyna: żądanie CORS nie powiodło się). Dowiedz się więcej - Oparty na chromium: dostęp do pobierania z źródła "https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5https://cors3.azurewebsites.net" został zablokowany przez zasady CORS: Odpowiedź na żądanie wstępne nie przekazuje kontroli dostępu: Brak nagłówka "Access-Control-Allow-Origin" dla żądanego zasobu. Jeśli nieprzezroczysta odpowiedź spełnia Twoje potrzeby, ustaw tryb żądania na wartość "no-cors", aby pobrać zasób z wyłączonym mechanizmem CORS.
Aby zezwolić na określone nagłówki, wywołaj metodę WithHeaders:
using Microsoft.Net.Http.Headers;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyAllowHeadersPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.WithHeaders(HeaderNames.ContentType, "x-custom-header");
});
});
builder.Services.AddControllers();
var app = builder.Build();
Aby zezwolić na wszystkie nagłówki żądań autora, wywołaj metodę AllowAnyHeader:
using Microsoft.Net.Http.Headers;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyAllowAllHeadersPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.AllowAnyHeader();
});
});
builder.Services.AddControllers();
var app = builder.Build();
Przeglądarki nie są spójne w sposobie ustawiania .Access-Control-Request-Headers
Jeśli:
- Nagłówki są ustawione na inne niż
"*"
- AllowAnyHeader jest wywoływany: uwzględnij co najmniej
Accept
,Content-Type
iOrigin
, oraz wszelkie nagłówki niestandardowe, które mają być obsługiwane.
Kod automatycznego żądania wstępnego
Po zastosowaniu zasad CORS:
- Globalnie przez wywołanie metody
app.UseCors
w plikuProgram.cs
. - Za pomocą atrybutu
[EnableCors]
.
ASP.NET Core odpowiada na żądanie OPCJE wstępne.
W sekcji Test CORS tego dokumentu pokazano to zachowanie.
[HttpOptions] atrybut dla żądań wstępnych
Gdy mechanizm CORS jest włączony z odpowiednimi zasadami, ASP.NET Core zwykle odpowiada na żądania wstępne CORS.
Poniższy kod używa atrybutu [HttpOptions] do tworzenia punktów końcowych dla żądań OPTIONS:
[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
// OPTIONS: api/TodoItems2/5
[HttpOptions("{id}")]
public IActionResult PreflightRoute(int id)
{
return NoContent();
}
// OPTIONS: api/TodoItems2
[HttpOptions]
public IActionResult PreflightRoute()
{
return NoContent();
}
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id)
{
if (id < 1)
{
return BadRequest();
}
return ControllerContext.MyDisplayRouteInfo(id);
}
Aby uzyskać instrukcje dotyczące testowania poprzedniego kodu, zobacz Testowanie mechanizmu CORS za pomocą atrybutu [EnableCors] i metody RequireCors.
Ustawianie czasu wygaśnięcia przedlotu
Nagłówek Access-Control-Max-Age
określa, jak długo można buforować odpowiedź na żądanie wstępne. Aby ustawić ten nagłówek, wywołaj metodę SetPreflightMaxAge:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MySetPreflightExpirationPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.SetPreflightMaxAge(TimeSpan.FromSeconds(2520));
});
});
builder.Services.AddControllers();
var app = builder.Build();
Włączanie mechanizmu CORS w punkcie końcowym
Jak działa mechanizm CORS
W tej sekcji opisano, co dzieje się w żądaniu CORS na poziomie komunikatów HTTP.
- MECHANIZM CORS nie jest funkcją zabezpieczeń. CORS to standard W3C, który umożliwia serwerowi złagodzenie zasad tego samego źródła.
- Na przykład złośliwy aktor może użyć skryptów między witrynami (XSS) w witrynie i wykonać żądanie obejmujące wiele witryn do witryny obsługującej mechanizm CORS w celu kradzieży informacji.
- Interfejs API nie jest bezpieczniejszy, zezwalając na mechanizm CORS.
- Do klienta (przeglądarki) należy wymuszenie mechanizmu CORS. Serwer wykonuje żądanie i zwraca odpowiedź— klient zwraca błąd i blokuje odpowiedź. Na przykład dowolne z następujących narzędzi wyświetli odpowiedź serwera:
- Fiddler
- .NET HttpClient
- Przeglądarka internetowa, wprowadzając adres URL na pasku adresu.
- Do klienta (przeglądarki) należy wymuszenie mechanizmu CORS. Serwer wykonuje żądanie i zwraca odpowiedź— klient zwraca błąd i blokuje odpowiedź. Na przykład dowolne z następujących narzędzi wyświetli odpowiedź serwera:
- Jest to sposób na serwer, aby umożliwić przeglądarkom wykonywanie między źródłami żądania XHR lub Fetch API , które w przeciwnym razie byłoby zabronione.
- Przeglądarki bez mechanizmu CORS nie mogą wykonywać żądań między źródłami. Przed mechanizmem CORS kod JSONP został użyty do obejścia tego ograniczenia. JSONP nie używa XHR, używa tagu
<script>
do odbierania odpowiedzi. Skrypty mogą być ładowane między źródłami.
- Przeglądarki bez mechanizmu CORS nie mogą wykonywać żądań między źródłami. Przed mechanizmem CORS kod JSONP został użyty do obejścia tego ograniczenia. JSONP nie używa XHR, używa tagu
Specyfikacja MECHANIZMU CORS wprowadziła kilka nowych nagłówków HTTP, które umożliwiają żądania między źródłami. Jeśli przeglądarka obsługuje mechanizm CORS, automatycznie ustawia te nagłówki dla żądań między źródłami. Niestandardowy kod JavaScript nie jest wymagany do włączenia mechanizmu CORS.
Poniżej przedstawiono przykład żądania między źródłami z przycisku Test wartości do https://cors1.azurewebsites.net/api/values
. Nagłówek Origin
:
- Udostępnia domenę lokacji wysyłającej żądanie.
- Jest wymagany i musi być inny niż host.
Nagłówki ogólne
Request URL: https://cors1.azurewebsites.net/api/values
Request Method: GET
Status Code: 200 OK
Nagłówki odpowiedzi
Content-Encoding: gzip
Content-Type: text/plain; charset=utf-8
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Transfer-Encoding: chunked
Vary: Accept-Encoding
X-Powered-By: ASP.NET
Nagłówki żądań
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Host: cors1.azurewebsites.net
Origin: https://cors3.azurewebsites.net
Referer: https://cors3.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 ...
W OPTIONS
żądaniach serwer ustawia nagłówek Nagłówki Access-Control-Allow-Origin: {allowed origin}
odpowiedzi w odpowiedzi. Na przykład w przykładowym kodzie Delete [EnableCors]
żądanie przycisku OPTIONS
zawiera następujące nagłówki:
Nagłówki ogólne
Request URL: https://cors3.azurewebsites.net/api/TodoItems2/MyDelete2/5
Request Method: OPTIONS
Status Code: 204 No Content
Nagłówki odpowiedzi
Access-Control-Allow-Headers: Content-Type,x-custom-header
Access-Control-Allow-Methods: PUT,DELETE,GET,OPTIONS
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors3.azurewebsites.net
Vary: Origin
X-Powered-By: ASP.NET
Nagłówki żądań
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: DELETE
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/test?number=2
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0
W poprzednich nagłówkach Odpowiedzi serwer ustawia nagłówek Access-Control-Allow-Origin w odpowiedzi. Wartość https://cors1.azurewebsites.net
tego nagłówka odpowiada nagłówkowi Origin
z żądania.
Jeśli AllowAnyOrigin parametr jest wywoływany, zwracana jest wartość z symbolem Access-Control-Allow-Origin: *
wieloznacznymi. AllowAnyOrigin
zezwala na dowolne źródło.
Jeśli odpowiedź nie zawiera nagłówka Access-Control-Allow-Origin
, żądanie między źródłami zakończy się niepowodzeniem. W szczególności przeglądarka nie zezwala na żądanie. Nawet jeśli serwer zwróci pomyślną odpowiedź, przeglądarka nie udostępni odpowiedzi aplikacji klienckiej.
Przekierowanie HTTP do protokołu HTTPS powoduje ERR_INVALID_REDIRECT w żądaniu wstępnym CORS
Żądania do punktu końcowego przy użyciu protokołu HTTP, które są przekierowywane do protokołu HTTPS przez UseHttpsRedirection niepowodzenie z .ERR_INVALID_REDIRECT on the CORS preflight request
Projekty interfejsu API mogą odrzucać żądania HTTP, a nie przekierowywać UseHttpsRedirection
żądania do protokołu HTTPS.
Mechanizm CORS w usługach IIS
Podczas wdrażania w usługach IIS mechanizm CORS musi działać przed uwierzytelnianiem systemu Windows, jeśli serwer nie jest skonfigurowany do zezwalania na dostęp anonimowy. Aby obsługiwać ten scenariusz, moduł CORS usług IIS musi zostać zainstalowany i skonfigurowany dla aplikacji.
Testowanie mechanizmu CORS
Przykładowy plik do pobrania zawiera kod do testowania mechanizmu CORS. Zobacz , jak pobrać. Przykład jest projektem interfejsu API z dodanymi stronami Razor :
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "MyPolicy",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com",
"https://cors1.azurewebsites.net",
"https://cors3.azurewebsites.net",
"https://localhost:44398",
"https://localhost:5001")
.WithMethods("PUT", "DELETE", "GET");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.MapRazorPages();
app.Run();
Ostrzeżenie
WithOrigins("https://localhost:<port>");
należy używać tylko do testowania przykładowej aplikacji podobnej do przykładowego kodu pobierania.
Poniżej przedstawiono ValuesController
punkty końcowe do testowania:
[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public IActionResult Get() =>
ControllerContext.MyDisplayRouteInfo();
// GET api/values/5
[HttpGet("{id}")]
public IActionResult Get(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// PUT api/values/5
[HttpPut("{id}")]
public IActionResult Put(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// GET: api/values/GetValues2
[DisableCors]
[HttpGet("{action}")]
public IActionResult GetValues2() =>
ControllerContext.MyDisplayRouteInfo();
}
MyDisplayRouteInfo jest dostarczany przez pakiet NuGet Rick.Docs.Samples.RouteInfo i wyświetla informacje o trasie.
Przetestuj poprzedni przykładowy kod przy użyciu jednego z następujących metod:
- Uruchom przykład przy
dotnet run
użyciu domyślnego adresu URL .https://localhost:5001
- Uruchom przykład z programu Visual Studio z portem ustawionym na 44398 jako adres URL
https://localhost:44398
.
Za pomocą przeglądarki z narzędziami F12:
Wybierz przycisk Wartości i przejrzyj nagłówki na karcie Sieć.
Wybierz przycisk TEST PUT. Zobacz Wyświetlanie żądań OPTIONS, aby uzyskać instrukcje dotyczące wyświetlania żądania OPTIONS. Test PUT tworzy dwa żądania, żądanie wstępne OPTIONS i żądanie PUT.
Wybierz przycisk,
GetValues2 [DisableCors]
aby wyzwolić nieudane żądanie CORS. Jak wspomniano w dokumencie, odpowiedź zwraca 200 powodzenia, ale żądanie CORS nie jest wykonywane. Wybierz kartę Konsola, aby wyświetlić błąd CORS. W zależności od przeglądarki zostanie wyświetlony błąd podobny do następującego:Dostęp do pobierania
'https://cors1.azurewebsites.net/api/values/GetValues2'
z źródła'https://cors3.azurewebsites.net'
został zablokowany przez zasady CORS: w żądanym zasobie nie ma nagłówka "Access-Control-Allow-Origin". Jeśli nieprzezroczysta odpowiedź spełnia Twoje potrzeby, ustaw tryb żądania na wartość "no-cors", aby pobrać zasób z wyłączonym mechanizmem CORS.
Punkty końcowe z obsługą mechanizmu CORS można przetestować za pomocą narzędzia, takiego jak curl lub Fiddler. W przypadku korzystania z narzędzia źródło żądania określonego przez Origin
nagłówek musi się różnić od hosta odbierającego żądanie. Jeśli żądanie nie jest źródłem krzyżowym na podstawie wartości nagłówka Origin
:
- Nie ma potrzeby przetwarzania żądania przez oprogramowanie pośredniczące CORS.
- Nagłówki CORS nie są zwracane w odpowiedzi.
Następujące polecenie używa curl
polecenia , aby wysłać żądanie OPTIONS z informacjami:
curl -X OPTIONS https://cors3.azurewebsites.net/api/TodoItems2/5 -i
Testowanie mechanizmu CORS za pomocą atrybutu [EnableCors] i metody RequireCors
Rozważmy następujący kod, który używa routingu punktów końcowych w celu włączenia mechanizmu CORS dla poszczególnych punktów końcowych przy użyciu polecenia RequireCors
:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "MyPolicy",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com",
"https://cors1.azurewebsites.net",
"https://cors3.azurewebsites.net",
"https://localhost:44398",
"https://localhost:5001")
.WithMethods("PUT", "DELETE", "GET");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/echo",
context => context.Response.WriteAsync("echo"))
.RequireCors("MyPolicy");
endpoints.MapControllers();
endpoints.MapRazorPages();
});
app.Run();
Zwróć uwagę, że tylko /echo
punkt końcowy używa elementu , RequireCors
aby zezwolić na żądania między źródłami przy użyciu określonych zasad. Poniższe kontrolery włączają mechanizm CORS przy użyciu atrybutu [EnableCors].
Poniżej przedstawiono TodoItems1Controller
punkty końcowe do testowania:
[Route("api/[controller]")]
[ApiController]
public class TodoItems1Controller : ControllerBase
{
// PUT: api/TodoItems1/5
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id) {
if (id < 1) {
return Content($"ID = {id}");
}
return ControllerContext.MyDisplayRouteInfo(id);
}
// Delete: api/TodoItems1/5
[HttpDelete("{id}")]
public IActionResult MyDelete(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// GET: api/TodoItems1
[HttpGet]
public IActionResult GetTodoItems() =>
ControllerContext.MyDisplayRouteInfo();
[EnableCors("MyPolicy")]
[HttpGet("{action}")]
public IActionResult GetTodoItems2() =>
ControllerContext.MyDisplayRouteInfo();
// Delete: api/TodoItems1/MyDelete2/5
[EnableCors("MyPolicy")]
[HttpDelete("{action}/{id}")]
public IActionResult MyDelete2(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
}
Przyciski Usuń [EnableCors] i GET [EnableCors] kończą się powodzeniem, ponieważ punkty końcowe mają [EnableCors]
żądania wstępne i odpowiadają na nie. Inne punkty końcowe kończą się niepowodzeniem. Przycisk GET kończy się niepowodzeniem, ponieważ skrypt JavaScript wysyła:
headers: {
"Content-Type": "x-custom-header"
},
Poniższe informacje TodoItems2Controller
zawierają podobne punkty końcowe, ale zawierają jawny kod, który odpowiada na żądania OPTIONS:
[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
// OPTIONS: api/TodoItems2/5
[HttpOptions("{id}")]
public IActionResult PreflightRoute(int id)
{
return NoContent();
}
// OPTIONS: api/TodoItems2
[HttpOptions]
public IActionResult PreflightRoute()
{
return NoContent();
}
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id)
{
if (id < 1)
{
return BadRequest();
}
return ControllerContext.MyDisplayRouteInfo(id);
}
// [EnableCors] // Not needed as OPTIONS path provided.
[HttpDelete("{id}")]
public IActionResult MyDelete(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// [EnableCors] // Warning ASP0023 Route '{id}' conflicts with another action route.
// An HTTP request that matches multiple routes results in an ambiguous
// match error.
[EnableCors("MyPolicy")] // Required for this path.
[HttpGet]
public IActionResult GetTodoItems() =>
ControllerContext.MyDisplayRouteInfo();
[HttpGet("{action}")]
public IActionResult GetTodoItems2() =>
ControllerContext.MyDisplayRouteInfo();
[EnableCors("MyPolicy")] // Required for this path.
[HttpDelete("{action}/{id}")]
public IActionResult MyDelete2(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
}
Powyższy kod można przetestować, wdrażając przykład na platformie Azure. Z listy rozwijanej Kontroler wybierz pozycję Wstępne, a następnie pozycję Ustaw kontroler. Wszystkie wywołania CORS do punktów końcowych kończą się powodzeniem TodoItems2Controller
.
Dodatkowe zasoby
Autorzy: Rick Anderson i Kirk Larkin
W tym artykule pokazano, jak włączyć mechanizm CORS w aplikacji ASP.NET Core.
Zabezpieczenia przeglądarki uniemożliwiają stronie internetowej wykonywanie żądań do innej domeny niż ta, która obsłużyła stronę internetową. To ograniczenie określa się jako zasadę tego samego źródła. Zasada tego samego źródła uniemożliwia złośliwym witrynom odczytywanie poufnych danych z innej witryny. Czasami możesz zezwolić innym witrynom na wykonywanie żądań w aplikacji o innym źródle. Aby uzyskać więcej informacji, zobacz artykuł Mozilla CORS.
Współużytkowanie zasobów między źródłami (CORS):
- Jest standardem W3C, który umożliwia serwerowi złagodzenie zasad tego samego źródła.
- Nie jest funkcją zabezpieczeń, mechanizm CORS zrelaksuje zabezpieczenia. Interfejs API nie jest bezpieczniejszy, zezwalając na mechanizm CORS. Aby uzyskać więcej informacji, zobacz Jak działa mechanizm CORS.
- Zezwala serwerowi na jawne zezwalanie na niektóre żądania między źródłami podczas odrzucania innych.
- Jest bezpieczniejszy i bardziej elastyczny niż wcześniejsze techniki, takie jak JSONP.
Wyświetl lub pobierz przykładowy kod (jak pobrać)
To samo źródło
Dwa adresy URL mają to samo źródło, jeśli mają identyczne schematy, hosty i porty (RFC 6454).
Te dwa adresy URL mają to samo źródło:
https://example.com/foo.html
https://example.com/bar.html
Te adresy URL mają inne źródła niż poprzednie dwa adresy URL:
https://example.net
: Inna domenahttps://www.example.com/foo.html
: Inna poddomenahttp://example.com/foo.html
: Inny schemathttps://example.com:9000/foo.html
: Inny port
Włączanie mechanizmu CORS
Istnieją trzy sposoby włączania mechanizmu CORS:
- W przypadku oprogramowania pośredniczącego przy użyciu nazwanych zasad lub zasad domyślnych.
- Korzystanie z routingu punktów końcowych.
- Za pomocą atrybutu [EnableCors].
Użycie atrybutu [EnableCors] z nazwanymi zasadami zapewnia najlepszą kontrolę w ograniczaniu punktów końcowych obsługujących mechanizm CORS.
Ostrzeżenie
UseCors musi być wywoływana w odpowiedniej kolejności. Aby uzyskać więcej informacji, zobacz Kolejność oprogramowania pośredniczącego. Na przykład UseCors
należy wywołać metodę przed UseResponseCaching użyciem polecenia UseResponseCaching
.
Każde podejście zostało szczegółowo opisane w poniższych sekcjach.
MECHANIZM CORS z nazwanymi zasadami i oprogramowaniem pośredniczącym
Oprogramowanie pośredniczące CORS obsługuje żądania między źródłami. Poniższy kod stosuje zasady CORS do wszystkich punktów końcowych aplikacji z określonymi źródłami:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
// services.AddResponseCaching();
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.MapControllers();
app.Run();
Powyższy kod ma następujące działanie:
- Ustawia nazwę zasad na
_myAllowSpecificOrigins
. Nazwa zasad jest dowolna. - Wywołuje metodę UseCors rozszerzenia i określa
_myAllowSpecificOrigins
zasady CORS.UseCors
dodaje oprogramowanie pośredniczące CORS. WywołanieUseCors
musi zostać umieszczone poUseRouting
metodzie , ale przedUseAuthorization
. Aby uzyskać więcej informacji, zobacz Kolejność oprogramowania pośredniczącego. - Wywołania AddCors za pomocą wyrażenia lambda. Lambda przyjmuje CorsPolicyBuilder obiekt. Opcje konfiguracji, takie jak
WithOrigins
, zostały opisane w dalszej części tego artykułu. _myAllowSpecificOrigins
Włącza zasady CORS dla wszystkich punktów końcowych kontrolera. Zobacz Routing punktów końcowych, aby zastosować zasady CORS do określonych punktów końcowych.- W przypadku korzystania z oprogramowania pośredniczącego buforowania odpowiedzi wywołaj metodę UseCors przed UseResponseCaching.
W przypadku routingu punktów końcowych oprogramowanie pośredniczące CORS musi być skonfigurowane do wykonywania między wywołaniami do UseRouting
i UseEndpoints
.
Wywołanie AddCors metody dodaje usługi CORS do kontenera usługi aplikacji:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
// services.AddResponseCaching();
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.MapControllers();
app.Run();
Aby uzyskać więcej informacji, zobacz opcje zasad MECHANIZMU CORS w tym dokumencie.
CorsPolicyBuilder Metody można połączyć łańcuchem, jak pokazano w poniższym kodzie:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.MapControllers();
app.Run();
Uwaga: określony adres URL nie może zawierać ukośnika końcowego (/
). Jeśli adres URL zakończy się ciągiem /
, porównanie zwróci wartość false
i nie zostanie zwrócony żaden nagłówek.
Ostrzeżenie
UseCors
należy umieścić po i UseRouting
przed UseAuthorization
. Ma to na celu zapewnienie, że nagłówki CORS znajdują się w odpowiedzi zarówno na wywołania autoryzowane, jak i nieautoryzowane.
Kolejność składników UseCors i UseStaticFiles
UseStaticFiles
Zazwyczaj jest wywoływana przed UseCors
. Aplikacje korzystające z języka JavaScript do pobierania plików statycznych między witrynami muszą wywoływać przed UseStaticFiles
.UseCors
MECHANIZM CORS z domyślnymi zasadami i oprogramowaniem pośredniczącym
Poniższy wyróżniony kod włącza domyślne zasady MECHANIZMU CORS:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.Run();
Powyższy kod stosuje domyślne zasady CORS do wszystkich punktów końcowych kontrolera.
Włączanie mechanizmu Cors z routingiem punktów końcowych
W przypadku routingu punktu końcowego mechanizm CORS można włączyć dla poszczególnych punktów końcowych przy użyciu RequireCors zestawu metod rozszerzeń:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/echo",
context => context.Response.WriteAsync("echo"))
.RequireCors(MyAllowSpecificOrigins);
endpoints.MapControllers()
.RequireCors(MyAllowSpecificOrigins);
endpoints.MapGet("/echo2",
context => context.Response.WriteAsync("echo2"));
endpoints.MapRazorPages();
});
app.Run();
Powyższy kod:
app.UseCors
włącza oprogramowanie pośredniczące CORS. Ponieważ nie skonfigurowano zasad domyślnych,app.UseCors()
sam nie włącza mechanizmu CORS.- Punkty
/echo
końcowe kontrolera i zezwalają na żądania między źródłami przy użyciu określonych zasad. - Punkty
/echo2
końcowe stron i Razor nie zezwalają na żądania między źródłami, ponieważ nie określono żadnych domyślnych zasad.
Atrybut [DisableCors] nie wyłącza mechanizmu CORS, który został włączony przez routing punktu końcowego za pomocą polecenia RequireCors
.
W ASP.NET Core 7.0 [EnableCors]
atrybut musi przekazać parametr lub ostrzeżenie ASP0023 jest generowane na podstawie niejednoznacznego dopasowania na trasie. program ASP.NET Core 8.0 lub nowszy nie generuje ASP0023
ostrzeżenia.
[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
// OPTIONS: api/TodoItems2/5
[HttpOptions("{id}")]
public IActionResult PreflightRoute(int id)
{
return NoContent();
}
// OPTIONS: api/TodoItems2
[HttpOptions]
public IActionResult PreflightRoute()
{
return NoContent();
}
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id)
{
if (id < 1)
{
return BadRequest();
}
return ControllerContext.MyDisplayRouteInfo(id);
}
// [EnableCors] // Not needed as OPTIONS path provided.
[HttpDelete("{id}")]
public IActionResult MyDelete(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// [EnableCors] // Warning ASP0023 Route '{id}' conflicts with another action route.
// An HTTP request that matches multiple routes results in an ambiguous
// match error.
[EnableCors("MyPolicy")] // Required for this path.
[HttpGet]
public IActionResult GetTodoItems() =>
ControllerContext.MyDisplayRouteInfo();
[HttpGet("{action}")]
public IActionResult GetTodoItems2() =>
ControllerContext.MyDisplayRouteInfo();
[EnableCors("MyPolicy")] // Required for this path.
[HttpDelete("{action}/{id}")]
public IActionResult MyDelete2(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
}
Zobacz Testowanie mechanizmu CORS za pomocą atrybutu [EnableCors] i metody RequireCors, aby uzyskać instrukcje dotyczące testowania kodu podobnego do poprzedniego.
Włączanie mechanizmu CORS z atrybutami
Włączenie mechanizmu CORS za pomocą atrybutu [EnableCors] i zastosowanie nazwanych zasad tylko do tych punktów końcowych, które wymagają mechanizmu CORS, zapewnia najlepszą kontrolę.
Atrybut [EnableCors] zapewnia alternatywę dla stosowania mechanizmu CORS globalnie. Atrybut [EnableCors]
umożliwia mechanizm CORS dla wybranych punktów końcowych, a nie wszystkich punktów końcowych:
[EnableCors]
określa zasady domyślne.[EnableCors("{Policy String}")]
określa nazwane zasady.
Atrybut [EnableCors]
można zastosować do:
- Razor Strona
PageModel
- Kontroler
- Metoda akcji kontrolera
Różne zasady można stosować do kontrolerów, modeli stron lub metod akcji za pomocą atrybutu [EnableCors]
. [EnableCors]
Gdy atrybut jest stosowany do kontrolera, modelu strony lub metody akcji, a mechanizm CORS jest włączony w programie pośredniczącym, stosowane są obie zasady. Zalecamy łączenie zasad. Użyj przycisku[EnableCors]
atrybutu lub oprogramowania pośredniczącego, a nie obu w tej samej aplikacji.
Poniższy kod stosuje inne zasady do każdej metody:
[Route("api/[controller]")]
[ApiController]
public class WidgetController : ControllerBase
{
// GET api/values
[EnableCors("AnotherPolicy")]
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "green widget", "red widget" };
}
// GET api/values/5
[EnableCors("Policy1")]
[HttpGet("{id}")]
public ActionResult<string> Get(int id)
{
return id switch
{
1 => "green widget",
2 => "red widget",
_ => NotFound(),
};
}
}
Poniższy kod tworzy dwie zasady CORS:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("Policy1",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
options.AddPolicy("AnotherPolicy",
policy =>
{
policy.WithOrigins("http://www.contoso.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.Run();
Aby uzyskać najlepszą kontrolę nad ograniczaniem żądań CORS:
- Użyj
[EnableCors("MyPolicy")]
z nazwanymi zasadami. - Nie należy definiować zasad domyślnych.
- Nie używaj routingu punktów końcowych.
Kod w następnej sekcji spełnia poprzednią listę.
Wyłączanie mechanizmu CORS
Atrybut [DisableCors] nie wyłącza mechanizmu CORS, który został włączony przez routing punktu końcowego.
Poniższy kod definiuje zasady "MyPolicy"
MECHANIZMU CORS:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "MyPolicy",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com")
.WithMethods("PUT", "DELETE", "GET");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints => {
endpoints.MapControllers();
endpoints.MapRazorPages();
});
app.Run();
Poniższy kod wyłącza mechanizm CORS dla GetValues2
akcji:
[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public IActionResult Get() =>
ControllerContext.MyDisplayRouteInfo();
// GET api/values/5
[HttpGet("{id}")]
public IActionResult Get(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// PUT api/values/5
[HttpPut("{id}")]
public IActionResult Put(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// GET: api/values/GetValues2
[DisableCors]
[HttpGet("{action}")]
public IActionResult GetValues2() =>
ControllerContext.MyDisplayRouteInfo();
}
Powyższy kod ma następujące działanie:
- Nie włącza mechanizmu CORS z routingiem punktów końcowych.
- Nie definiuje domyślnych zasad CORS.
- Używa funkcji [EnableCors("MyPolicy")] w celu włączenia
"MyPolicy"
zasad CORS dla kontrolera. - Wyłącza mechanizm CORS dla
GetValues2
metody .
Aby uzyskać instrukcje dotyczące testowania poprzedniego kodu, zobacz Testowanie mechanizmu CORS .
Opcje zasad MECHANIZMU CORS
W tej sekcji opisano różne opcje, które można ustawić w zasadach MECHANIZMU CORS:
- Ustawianie dozwolonych źródeł
- Ustawianie dozwolonych metod HTTP
- Ustawianie dozwolonych nagłówków żądań
- Ustawianie uwidocznionych nagłówków odpowiedzi
- Poświadczenia w żądaniach między źródłami
- Ustawianie czasu wygaśnięcia przedlotu
AddPolicy jest wywoływana w pliku Program.cs
. W przypadku niektórych opcji warto zapoznać się z sekcją Jak działa mechanizm CORS.
Ustawianie dozwolonych źródeł
AllowAnyOrigin: zezwala na żądania CORS ze wszystkich źródeł przy użyciu dowolnego schematu (http
lub https
). AllowAnyOrigin
jest niezabezpieczona, ponieważ każda witryna internetowa może wysyłać żądania między źródłami do aplikacji.
Uwaga
Określanie AllowAnyOrigin
i AllowCredentials
jest niezabezpieczoną konfiguracją i może spowodować fałszerzowanie żądań między witrynami. Usługa CORS zwraca nieprawidłową odpowiedź CORS, gdy aplikacja jest skonfigurowana przy użyciu obu metod.
AllowAnyOrigin
dotyczy żądań wstępnych i nagłówka Access-Control-Allow-Origin
. Aby uzyskać więcej informacji, zobacz sekcję Wstępne żądania .
SetIsOriginAllowedToAllowWildcardSubdomains: Ustawia IsOriginAllowed właściwość zasad jako funkcję, która umożliwia źródłom dopasowanie skonfigurowanej domeny wieloznacznych podczas oceny, czy źródło jest dozwolone.
var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("https://*.example.com")
.SetIsOriginAllowedToAllowWildcardSubdomains();
});
});
builder.Services.AddControllers();
var app = builder.Build();
Ustawianie dozwolonych metod HTTP
- Zezwala na dowolną metodę HTTP:
- Wpływa na żądania wstępne i
Access-Control-Allow-Methods
nagłówek. Aby uzyskać więcej informacji, zobacz sekcję Wstępne żądania .
Ustawianie dozwolonych nagłówków żądań
Aby zezwolić na wysyłanie określonych nagłówków w żądaniu CORS, nazywanym nagłówkami żądań autora, wywołaj WithHeaders i określ dozwolone nagłówki:
using Microsoft.Net.Http.Headers;
var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com")
.WithHeaders(HeaderNames.ContentType, "x-custom-header");
});
});
builder.Services.AddControllers();
var app = builder.Build();
Aby zezwolić na wszystkie nagłówki żądań autora, wywołaj metodę AllowAnyHeader:
var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("https://*.example.com")
.AllowAnyHeader();
});
});
builder.Services.AddControllers();
var app = builder.Build();
AllowAnyHeader
dotyczy żądań wstępnych i nagłówka Access-Control-Request-Headers . Aby uzyskać więcej informacji, zobacz sekcję Wstępne żądania .
Zasady oprogramowania pośredniczącego CORS są zgodne z określonymi nagłówkami określonymi przez WithHeaders
usługę jest możliwe tylko wtedy, gdy nagłówki wysyłane w Access-Control-Request-Headers
formacie dokładnie odpowiadają nagłówkom określonym w elemencie WithHeaders
.
Rozważmy na przykład aplikację skonfigurowaną w następujący sposób:
app.UseCors(policy => policy.WithHeaders(HeaderNames.CacheControl));
Oprogramowanie pośredniczące CORS odrzuca żądanie wstępne z następującym nagłówkiem żądania, ponieważ Content-Language
(HeaderNames.ContentLanguage) nie ma na liście :WithHeaders
Access-Control-Request-Headers: Cache-Control, Content-Language
Aplikacja zwraca odpowiedź 200 OK , ale nie wysyła nagłówków CORS z powrotem. W związku z tym przeglądarka nie podejmuje próby żądania między źródłami.
Ustawianie uwidocznionych nagłówków odpowiedzi
Domyślnie przeglądarka nie ujawnia wszystkich nagłówków odpowiedzi aplikacji. Aby uzyskać więcej informacji, zobacz Udostępnianie zasobów między źródłami W3C (terminologia): prosty nagłówek odpowiedzi.
Nagłówki odpowiedzi, które są dostępne domyślnie, to:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
Specyfikacja MECHANIZMU CORS wywołuje te nagłówki prostych nagłówków odpowiedzi. Aby udostępnić inne nagłówki aplikacji, wywołaj metodę WithExposedHeaders:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyExposeResponseHeadersPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.WithExposedHeaders("x-custom-header");
});
});
builder.Services.AddControllers();
var app = builder.Build();
Poświadczenia w żądaniach między źródłami
Poświadczenia wymagają specjalnej obsługi w żądaniu CORS. Domyślnie przeglądarka nie wysyła poświadczeń z żądaniem między źródłami. Poświadczenia obejmują pliki cookie i schematy uwierzytelniania HTTP. Aby wysyłać poświadczenia z żądaniem między źródłami, klient musi ustawić wartość XMLHttpRequest.withCredentials
true
.
Bezpośrednie użycie XMLHttpRequest
:
var xhr = new XMLHttpRequest();
xhr.open('get', 'https://www.example.com/api/test');
xhr.withCredentials = true;
Korzystanie z zapytania jQuery:
$.ajax({
type: 'get',
url: 'https://www.example.com/api/test',
xhrFields: {
withCredentials: true
}
});
Korzystanie z interfejsu API pobierania:
fetch('https://www.example.com/api/test', {
credentials: 'include'
});
Serwer musi zezwalać na poświadczenia. Aby zezwolić na poświadczenia między źródłami, wywołaj metodę AllowCredentials:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyMyAllowCredentialsPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.AllowCredentials();
});
});
builder.Services.AddControllers();
var app = builder.Build();
Odpowiedź HTTP zawiera Access-Control-Allow-Credentials
nagłówek, który informuje przeglądarkę, że serwer zezwala na poświadczenia dla żądania między źródłami.
Jeśli przeglądarka wysyła poświadczenia, ale odpowiedź nie zawiera prawidłowego Access-Control-Allow-Credentials
nagłówka, przeglądarka nie uwidacznia odpowiedzi na aplikację, a żądanie między źródłami zakończy się niepowodzeniem.
Zezwolenie na poświadczenia między źródłami jest zagrożeniem bezpieczeństwa. Witryna internetowa w innej domenie może wysyłać poświadczenia zalogowanego użytkownika do aplikacji w imieniu użytkownika bez wiedzy użytkownika.
Specyfikacja MECHANIZMU CORS stwierdza również, że ustawienie wartości origins na "*"
(wszystkie źródła) jest nieprawidłowe, jeśli Access-Control-Allow-Credentials
nagłówek jest obecny.
Żądania wstępne
W przypadku niektórych żądań CORS przeglądarka wysyła dodatkowe żądanie OPTIONS przed wysłaniem rzeczywistego żądania. To żądanie jest nazywane żądaniem wstępnym. Przeglądarka może pominąć żądanie wstępne, jeśli spełnione są wszystkie następujące warunki:
- Metoda żądania to GET, HEAD lub POST.
- Aplikacja nie ustawia nagłówków żądań innych niż
Accept
, ,Accept-Language
,Content-Language
,Content-Type
lubLast-Event-ID
. - Nagłówek
Content-Type
, jeśli jest ustawiony, ma jedną z następujących wartości:application/x-www-form-urlencoded
multipart/form-data
text/plain
Reguła nagłówków żądań ustawiona dla żądania klienta ma zastosowanie do nagłówków ustawianych przez aplikację przez wywołanie setRequestHeader
XMLHttpRequest
obiektu. Specyfikacja MECHANIZMU CORS wywołuje te nagłówki żądań autora. Reguła nie ma zastosowania do nagłówków, które można ustawić w przeglądarce, takich jak User-Agent
, Host
lub Content-Length
.
Poniżej przedstawiono przykładową odpowiedź podobną do żądania wstępnego wykonanego z przycisku [Put test] w sekcji Test CORS tego dokumentu.
General:
Request URL: https://cors3.azurewebsites.net/api/values/5
Request Method: OPTIONS
Status Code: 204 No Content
Response Headers:
Access-Control-Allow-Methods: PUT,DELETE,GET
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f8...8;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Vary: Origin
Request Headers:
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Method: PUT
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0
Żądanie wstępne używa metody HTTP OPTIONS . Może zawierać następujące nagłówki:
- Access-Control-Request-Method: metoda HTTP, która będzie używana dla rzeczywistego żądania.
- Access-Control-Request-Headers: lista nagłówków żądań ustawianych przez aplikację w rzeczywistym żądaniu. Jak wspomniano wcześniej, nie zawiera to nagłówków ustawionych przez przeglądarkę, takich jak
User-Agent
. - Access-Control-Allow-Methods
Jeśli żądanie wstępne zostanie odrzucone, aplikacja zwróci 200 OK
odpowiedź, ale nie ustawi nagłówków CORS. W związku z tym przeglądarka nie podejmuje próby żądania między źródłami. Aby zapoznać się z przykładem odmowy żądania wstępnego, zobacz sekcję Test CORS tego dokumentu.
Za pomocą narzędzi F12 aplikacja konsolowa wyświetla błąd podobny do jednego z następujących, w zależności od przeglądarki:
- Firefox: Żądanie między źródłami zablokowane: Te same zasady pochodzenia nie zezwalają na odczytywanie zasobu zdalnego pod adresem
https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5
. (Przyczyna: żądanie CORS nie powiodło się). Dowiedz się więcej - Oparty na chromium: dostęp do pobierania z źródła "https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5https://cors3.azurewebsites.net" został zablokowany przez zasady CORS: Odpowiedź na żądanie wstępne nie przekazuje kontroli dostępu: Brak nagłówka "Access-Control-Allow-Origin" dla żądanego zasobu. Jeśli nieprzezroczysta odpowiedź spełnia Twoje potrzeby, ustaw tryb żądania na wartość "no-cors", aby pobrać zasób z wyłączonym mechanizmem CORS.
Aby zezwolić na określone nagłówki, wywołaj metodę WithHeaders:
using Microsoft.Net.Http.Headers;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyAllowHeadersPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.WithHeaders(HeaderNames.ContentType, "x-custom-header");
});
});
builder.Services.AddControllers();
var app = builder.Build();
Aby zezwolić na wszystkie nagłówki żądań autora, wywołaj metodę AllowAnyHeader:
using Microsoft.Net.Http.Headers;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyAllowAllHeadersPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.AllowAnyHeader();
});
});
builder.Services.AddControllers();
var app = builder.Build();
Przeglądarki nie są spójne w sposobie ustawiania .Access-Control-Request-Headers
Jeśli:
- Nagłówki są ustawione na inne niż
"*"
- AllowAnyHeader jest wywoływany: uwzględnij co najmniej
Accept
,Content-Type
iOrigin
, oraz wszelkie nagłówki niestandardowe, które mają być obsługiwane.
Kod automatycznego żądania wstępnego
Po zastosowaniu zasad CORS:
- Globalnie przez wywołanie metody
app.UseCors
w plikuProgram.cs
. - Za pomocą atrybutu
[EnableCors]
.
ASP.NET Core odpowiada na żądanie OPCJE wstępne.
W sekcji Test CORS tego dokumentu pokazano to zachowanie.
[HttpOptions] atrybut dla żądań wstępnych
Gdy mechanizm CORS jest włączony z odpowiednimi zasadami, ASP.NET Core zwykle odpowiada na żądania wstępne CORS.
Poniższy kod używa atrybutu [HttpOptions] do tworzenia punktów końcowych dla żądań OPTIONS:
[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
// OPTIONS: api/TodoItems2/5
[HttpOptions("{id}")]
public IActionResult PreflightRoute(int id)
{
return NoContent();
}
// OPTIONS: api/TodoItems2
[HttpOptions]
public IActionResult PreflightRoute()
{
return NoContent();
}
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id)
{
if (id < 1)
{
return BadRequest();
}
return ControllerContext.MyDisplayRouteInfo(id);
}
Aby uzyskać instrukcje dotyczące testowania poprzedniego kodu, zobacz Testowanie mechanizmu CORS za pomocą atrybutu [EnableCors] i metody RequireCors.
Ustawianie czasu wygaśnięcia przedlotu
Nagłówek Access-Control-Max-Age
określa, jak długo można buforować odpowiedź na żądanie wstępne. Aby ustawić ten nagłówek, wywołaj metodę SetPreflightMaxAge:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MySetPreflightExpirationPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.SetPreflightMaxAge(TimeSpan.FromSeconds(2520));
});
});
builder.Services.AddControllers();
var app = builder.Build();
Włączanie mechanizmu CORS w punkcie końcowym
Jak działa mechanizm CORS
W tej sekcji opisano, co dzieje się w żądaniu CORS na poziomie komunikatów HTTP.
- MECHANIZM CORS nie jest funkcją zabezpieczeń. CORS to standard W3C, który umożliwia serwerowi złagodzenie zasad tego samego źródła.
- Na przykład złośliwy aktor może użyć skryptów między witrynami (XSS) w witrynie i wykonać żądanie obejmujące wiele witryn do witryny obsługującej mechanizm CORS w celu kradzieży informacji.
- Interfejs API nie jest bezpieczniejszy, zezwalając na mechanizm CORS.
- Do klienta (przeglądarki) należy wymuszenie mechanizmu CORS. Serwer wykonuje żądanie i zwraca odpowiedź— klient zwraca błąd i blokuje odpowiedź. Na przykład dowolne z następujących narzędzi wyświetli odpowiedź serwera:
- Fiddler
- .NET HttpClient
- Przeglądarka internetowa, wprowadzając adres URL na pasku adresu.
- Do klienta (przeglądarki) należy wymuszenie mechanizmu CORS. Serwer wykonuje żądanie i zwraca odpowiedź— klient zwraca błąd i blokuje odpowiedź. Na przykład dowolne z następujących narzędzi wyświetli odpowiedź serwera:
- Jest to sposób na serwer, aby umożliwić przeglądarkom wykonywanie między źródłami żądania XHR lub Fetch API , które w przeciwnym razie byłoby zabronione.
- Przeglądarki bez mechanizmu CORS nie mogą wykonywać żądań między źródłami. Przed mechanizmem CORS kod JSONP został użyty do obejścia tego ograniczenia. JSONP nie używa XHR, używa tagu
<script>
do odbierania odpowiedzi. Skrypty mogą być ładowane między źródłami.
- Przeglądarki bez mechanizmu CORS nie mogą wykonywać żądań między źródłami. Przed mechanizmem CORS kod JSONP został użyty do obejścia tego ograniczenia. JSONP nie używa XHR, używa tagu
Specyfikacja MECHANIZMU CORS wprowadziła kilka nowych nagłówków HTTP, które umożliwiają żądania między źródłami. Jeśli przeglądarka obsługuje mechanizm CORS, automatycznie ustawia te nagłówki dla żądań między źródłami. Niestandardowy kod JavaScript nie jest wymagany do włączenia mechanizmu CORS.
Wybierz przycisk TEST PUT w wdrożonym przykładzie.
Nagłówek Origin
:
- Udostępnia domenę lokacji wysyłającej żądanie.
- Jest wymagany i musi być inny niż host.
Nagłówki ogólne
Request URL: https://cors1.azurewebsites.net/api/values
Request Method: GET
Status Code: 200 OK
Nagłówki odpowiedzi
Content-Encoding: gzip
Content-Type: text/plain; charset=utf-8
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Transfer-Encoding: chunked
Vary: Accept-Encoding
X-Powered-By: ASP.NET
Nagłówki żądań
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Host: cors1.azurewebsites.net
Origin: https://cors3.azurewebsites.net
Referer: https://cors3.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 ...
W OPTIONS
żądaniach serwer ustawia nagłówek Nagłówki Access-Control-Allow-Origin: {allowed origin}
odpowiedzi w odpowiedzi. Na przykład w przykładowym kodzie Delete [EnableCors]
żądanie przycisku OPTIONS
zawiera następujące nagłówki:
Nagłówki ogólne
Request URL: https://cors3.azurewebsites.net/api/TodoItems2/MyDelete2/5
Request Method: OPTIONS
Status Code: 204 No Content
Nagłówki odpowiedzi
Access-Control-Allow-Headers: Content-Type,x-custom-header
Access-Control-Allow-Methods: PUT,DELETE,GET,OPTIONS
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors3.azurewebsites.net
Vary: Origin
X-Powered-By: ASP.NET
Nagłówki żądań
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: DELETE
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/test?number=2
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0
W poprzednich nagłówkach Odpowiedzi serwer ustawia nagłówek Access-Control-Allow-Origin w odpowiedzi. Wartość https://cors1.azurewebsites.net
tego nagłówka odpowiada nagłówkowi Origin
z żądania.
Jeśli AllowAnyOrigin parametr jest wywoływany, zwracana jest wartość z symbolem Access-Control-Allow-Origin: *
wieloznacznymi. AllowAnyOrigin
zezwala na dowolne źródło.
Jeśli odpowiedź nie zawiera nagłówka Access-Control-Allow-Origin
, żądanie między źródłami zakończy się niepowodzeniem. W szczególności przeglądarka nie zezwala na żądanie. Nawet jeśli serwer zwróci pomyślną odpowiedź, przeglądarka nie udostępni odpowiedzi aplikacji klienckiej.
Przekierowanie HTTP do protokołu HTTPS powoduje ERR_INVALID_REDIRECT w żądaniu wstępnym CORS
Żądania do punktu końcowego przy użyciu protokołu HTTP, które są przekierowywane do protokołu HTTPS przez UseHttpsRedirection niepowodzenie z .ERR_INVALID_REDIRECT on the CORS preflight request
Projekty interfejsu API mogą odrzucać żądania HTTP, a nie przekierowywać UseHttpsRedirection
żądania do protokołu HTTPS.
Mechanizm CORS w usługach IIS
Podczas wdrażania w usługach IIS mechanizm CORS musi działać przed uwierzytelnianiem systemu Windows, jeśli serwer nie jest skonfigurowany do zezwalania na dostęp anonimowy. Aby obsługiwać ten scenariusz, moduł CORS usług IIS musi zostać zainstalowany i skonfigurowany dla aplikacji.
Testowanie mechanizmu CORS
Przykładowy plik do pobrania zawiera kod do testowania mechanizmu CORS. Zobacz , jak pobrać. Przykład jest projektem interfejsu API z dodanymi stronami Razor :
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "MyPolicy",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com",
"https://cors1.azurewebsites.net",
"https://cors3.azurewebsites.net",
"https://localhost:44398",
"https://localhost:5001")
.WithMethods("PUT", "DELETE", "GET");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.MapRazorPages();
app.Run();
Ostrzeżenie
WithOrigins("https://localhost:<port>");
należy używać tylko do testowania przykładowej aplikacji podobnej do przykładowego kodu pobierania.
Poniżej przedstawiono ValuesController
punkty końcowe do testowania:
[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public IActionResult Get() =>
ControllerContext.MyDisplayRouteInfo();
// GET api/values/5
[HttpGet("{id}")]
public IActionResult Get(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// PUT api/values/5
[HttpPut("{id}")]
public IActionResult Put(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// GET: api/values/GetValues2
[DisableCors]
[HttpGet("{action}")]
public IActionResult GetValues2() =>
ControllerContext.MyDisplayRouteInfo();
}
MyDisplayRouteInfo jest dostarczany przez pakiet NuGet Rick.Docs.Samples.RouteInfo i wyświetla informacje o trasie.
Przetestuj poprzedni przykładowy kod przy użyciu jednego z następujących metod:
- Uruchom przykład przy
dotnet run
użyciu domyślnego adresu URL .https://localhost:5001
- Uruchom przykład z programu Visual Studio z portem ustawionym na 44398 jako adres URL
https://localhost:44398
.
Za pomocą przeglądarki z narzędziami F12:
Wybierz przycisk Wartości i przejrzyj nagłówki na karcie Sieć.
Wybierz przycisk TEST PUT. Zobacz Wyświetlanie żądań OPTIONS, aby uzyskać instrukcje dotyczące wyświetlania żądania OPTIONS. Test PUT tworzy dwa żądania, żądanie wstępne OPTIONS i żądanie PUT.
Wybierz przycisk,
GetValues2 [DisableCors]
aby wyzwolić nieudane żądanie CORS. Jak wspomniano w dokumencie, odpowiedź zwraca 200 powodzenia, ale żądanie CORS nie jest wykonywane. Wybierz kartę Konsola, aby wyświetlić błąd CORS. W zależności od przeglądarki zostanie wyświetlony błąd podobny do następującego:Dostęp do pobierania
'https://cors1.azurewebsites.net/api/values/GetValues2'
z źródła'https://cors3.azurewebsites.net'
został zablokowany przez zasady CORS: w żądanym zasobie nie ma nagłówka "Access-Control-Allow-Origin". Jeśli nieprzezroczysta odpowiedź spełnia Twoje potrzeby, ustaw tryb żądania na wartość "no-cors", aby pobrać zasób z wyłączonym mechanizmem CORS.
Punkty końcowe z obsługą mechanizmu CORS można przetestować za pomocą narzędzia, takiego jak curl lub Fiddler. W przypadku korzystania z narzędzia źródło żądania określonego przez Origin
nagłówek musi się różnić od hosta odbierającego żądanie. Jeśli żądanie nie jest źródłem krzyżowym na podstawie wartości nagłówka Origin
:
- Nie ma potrzeby przetwarzania żądania przez oprogramowanie pośredniczące CORS.
- Nagłówki CORS nie są zwracane w odpowiedzi.
Następujące polecenie używa curl
polecenia , aby wysłać żądanie OPTIONS z informacjami:
curl -X OPTIONS https://cors3.azurewebsites.net/api/TodoItems2/5 -i
Testowanie mechanizmu CORS za pomocą atrybutu [EnableCors] i metody RequireCors
Rozważmy następujący kod, który używa routingu punktów końcowych w celu włączenia mechanizmu CORS dla poszczególnych punktów końcowych przy użyciu polecenia RequireCors
:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "MyPolicy",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com",
"https://cors1.azurewebsites.net",
"https://cors3.azurewebsites.net",
"https://localhost:44398",
"https://localhost:5001")
.WithMethods("PUT", "DELETE", "GET");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/echo",
context => context.Response.WriteAsync("echo"))
.RequireCors("MyPolicy");
endpoints.MapControllers();
endpoints.MapRazorPages();
});
app.Run();
Zwróć uwagę, że tylko /echo
punkt końcowy używa elementu , RequireCors
aby zezwolić na żądania między źródłami przy użyciu określonych zasad. Poniższe kontrolery włączają mechanizm CORS przy użyciu atrybutu [EnableCors].
Poniżej przedstawiono TodoItems1Controller
punkty końcowe do testowania:
[Route("api/[controller]")]
[ApiController]
public class TodoItems1Controller : ControllerBase
{
// PUT: api/TodoItems1/5
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id) {
if (id < 1) {
return Content($"ID = {id}");
}
return ControllerContext.MyDisplayRouteInfo(id);
}
// Delete: api/TodoItems1/5
[HttpDelete("{id}")]
public IActionResult MyDelete(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// GET: api/TodoItems1
[HttpGet]
public IActionResult GetTodoItems() =>
ControllerContext.MyDisplayRouteInfo();
[EnableCors("MyPolicy")]
[HttpGet("{action}")]
public IActionResult GetTodoItems2() =>
ControllerContext.MyDisplayRouteInfo();
// Delete: api/TodoItems1/MyDelete2/5
[EnableCors("MyPolicy")]
[HttpDelete("{action}/{id}")]
public IActionResult MyDelete2(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
}
Przyciski Usuń [EnableCors] i GET [EnableCors] kończą się powodzeniem, ponieważ punkty końcowe mają [EnableCors]
żądania wstępne i odpowiadają na nie. Inne punkty końcowe kończą się niepowodzeniem. Przycisk GET kończy się niepowodzeniem, ponieważ skrypt JavaScript wysyła:
headers: {
"Content-Type": "x-custom-header"
},
Poniższe informacje TodoItems2Controller
zawierają podobne punkty końcowe, ale zawierają jawny kod, który odpowiada na żądania OPTIONS:
[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
// OPTIONS: api/TodoItems2/5
[HttpOptions("{id}")]
public IActionResult PreflightRoute(int id)
{
return NoContent();
}
// OPTIONS: api/TodoItems2
[HttpOptions]
public IActionResult PreflightRoute()
{
return NoContent();
}
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id)
{
if (id < 1)
{
return BadRequest();
}
return ControllerContext.MyDisplayRouteInfo(id);
}
// [EnableCors] // Not needed as OPTIONS path provided.
[HttpDelete("{id}")]
public IActionResult MyDelete(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// [EnableCors] // Warning ASP0023 Route '{id}' conflicts with another action route.
// An HTTP request that matches multiple routes results in an ambiguous
// match error.
[EnableCors("MyPolicy")] // Required for this path.
[HttpGet]
public IActionResult GetTodoItems() =>
ControllerContext.MyDisplayRouteInfo();
[HttpGet("{action}")]
public IActionResult GetTodoItems2() =>
ControllerContext.MyDisplayRouteInfo();
[EnableCors("MyPolicy")] // Required for this path.
[HttpDelete("{action}/{id}")]
public IActionResult MyDelete2(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
}
Powyższy kod można przetestować, wdrażając przykład w celu Azure.In listy rozwijanej Kontroler, wybierz pozycję Wstępne, a następnie ustaw kontroler. Wszystkie wywołania CORS do punktów końcowych kończą się powodzeniem TodoItems2Controller
.
Dodatkowe zasoby
Autorzy: Rick Anderson i Kirk Larkin
W tym artykule pokazano, jak włączyć mechanizm CORS w aplikacji ASP.NET Core.
Zabezpieczenia przeglądarki uniemożliwiają stronie internetowej wykonywanie żądań do innej domeny niż ta, która obsłużyła stronę internetową. To ograniczenie określa się jako zasadę tego samego źródła. Zasada tego samego źródła uniemożliwia złośliwym witrynom odczytywanie poufnych danych z innej witryny. Czasami możesz zezwolić innym witrynom na wykonywanie żądań w aplikacji o innym źródle. Aby uzyskać więcej informacji, zobacz artykuł Mozilla CORS.
Współużytkowanie zasobów między źródłami (CORS):
- Jest standardem W3C, który umożliwia serwerowi złagodzenie zasad tego samego źródła.
- Nie jest funkcją zabezpieczeń, mechanizm CORS zrelaksuje zabezpieczenia. Interfejs API nie jest bezpieczniejszy, zezwalając na mechanizm CORS. Aby uzyskać więcej informacji, zobacz Jak działa mechanizm CORS.
- Zezwala serwerowi na jawne zezwalanie na niektóre żądania między źródłami podczas odrzucania innych.
- Jest bezpieczniejszy i bardziej elastyczny niż wcześniejsze techniki, takie jak JSONP.
Wyświetl lub pobierz przykładowy kod (jak pobrać)
To samo źródło
Dwa adresy URL mają to samo źródło, jeśli mają identyczne schematy, hosty i porty (RFC 6454).
Te dwa adresy URL mają to samo źródło:
https://example.com/foo.html
https://example.com/bar.html
Te adresy URL mają inne źródła niż poprzednie dwa adresy URL:
https://example.net
: Inna domenahttps://www.example.com/foo.html
: Inna poddomenahttp://example.com/foo.html
: Inny schemathttps://example.com:9000/foo.html
: Inny port
Włączanie mechanizmu CORS
Istnieją trzy sposoby włączania mechanizmu CORS:
- W przypadku oprogramowania pośredniczącego przy użyciu nazwanych zasad lub zasad domyślnych.
- Korzystanie z routingu punktów końcowych.
- Za pomocą atrybutu [EnableCors].
Użycie atrybutu [EnableCors] z nazwanymi zasadami zapewnia najlepszą kontrolę w ograniczaniu punktów końcowych obsługujących mechanizm CORS.
Ostrzeżenie
UseCors musi być wywoływana w odpowiedniej kolejności. Aby uzyskać więcej informacji, zobacz Kolejność oprogramowania pośredniczącego. Na przykład UseCors
należy wywołać metodę przed UseResponseCaching użyciem polecenia UseResponseCaching
.
Każde podejście zostało szczegółowo opisane w poniższych sekcjach.
MECHANIZM CORS z nazwanymi zasadami i oprogramowaniem pośredniczącym
Oprogramowanie pośredniczące CORS obsługuje żądania między źródłami. Poniższy kod stosuje zasady CORS do wszystkich punktów końcowych aplikacji z określonymi źródłami:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
// services.AddResponseCaching();
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.MapControllers();
app.Run();
Powyższy kod ma następujące działanie:
- Ustawia nazwę zasad na
_myAllowSpecificOrigins
. Nazwa zasad jest dowolna. - Wywołuje metodę UseCors rozszerzenia i określa
_myAllowSpecificOrigins
zasady CORS.UseCors
dodaje oprogramowanie pośredniczące CORS. WywołanieUseCors
musi zostać umieszczone poUseRouting
metodzie , ale przedUseAuthorization
. Aby uzyskać więcej informacji, zobacz Kolejność oprogramowania pośredniczącego. - Wywołania AddCors za pomocą wyrażenia lambda. Lambda przyjmuje CorsPolicyBuilder obiekt. Opcje konfiguracji, takie jak
WithOrigins
, zostały opisane w dalszej części tego artykułu. _myAllowSpecificOrigins
Włącza zasady CORS dla wszystkich punktów końcowych kontrolera. Zobacz Routing punktów końcowych, aby zastosować zasady CORS do określonych punktów końcowych.- W przypadku korzystania z oprogramowania pośredniczącego buforowania odpowiedzi wywołaj metodę UseCors przed UseResponseCaching.
W przypadku routingu punktów końcowych oprogramowanie pośredniczące CORS musi być skonfigurowane do wykonywania między wywołaniami do UseRouting
i UseEndpoints
.
Wywołanie AddCors metody dodaje usługi CORS do kontenera usługi aplikacji:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
// services.AddResponseCaching();
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.MapControllers();
app.Run();
Aby uzyskać więcej informacji, zobacz opcje zasad MECHANIZMU CORS w tym dokumencie.
CorsPolicyBuilder Metody można połączyć łańcuchem, jak pokazano w poniższym kodzie:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
app.UseAuthorization();
app.MapControllers();
app.Run();
Uwaga: określony adres URL nie może zawierać ukośnika końcowego (/
). Jeśli adres URL zakończy się ciągiem /
, porównanie zwróci wartość false
i nie zostanie zwrócony żaden nagłówek.
Ostrzeżenie
UseCors
należy umieścić po i UseRouting
przed UseAuthorization
. Ma to na celu zapewnienie, że nagłówki CORS znajdują się w odpowiedzi zarówno na wywołania autoryzowane, jak i nieautoryzowane.
Kolejność składników UseCors i UseStaticFiles
UseStaticFiles
Zazwyczaj jest wywoływana przed UseCors
. Aplikacje korzystające z języka JavaScript do pobierania plików statycznych między witrynami muszą wywoływać przed UseStaticFiles
.UseCors
MECHANIZM CORS z domyślnymi zasadami i oprogramowaniem pośredniczącym
Poniższy wyróżniony kod włącza domyślne zasady MECHANIZMU CORS:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.Run();
Powyższy kod stosuje domyślne zasady CORS do wszystkich punktów końcowych kontrolera.
Włączanie mechanizmu Cors z routingiem punktów końcowych
Włączenie mechanizmu CORS dla poszczególnych punktów końcowych przy użyciu RequireCors
nie obsługuje automatycznych żądań wstępnych. Aby uzyskać więcej informacji, zobacz ten problem z usługą GitHub i Przetestuj mechanizm CORS z routingiem punktów końcowych i [HttpOptions].
W przypadku routingu punktu końcowego mechanizm CORS można włączyć dla poszczególnych punktów końcowych przy użyciu RequireCors zestawu metod rozszerzeń:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/echo",
context => context.Response.WriteAsync("echo"))
.RequireCors(MyAllowSpecificOrigins);
endpoints.MapControllers()
.RequireCors(MyAllowSpecificOrigins);
endpoints.MapGet("/echo2",
context => context.Response.WriteAsync("echo2"));
endpoints.MapRazorPages();
});
app.Run();
Powyższy kod:
app.UseCors
włącza oprogramowanie pośredniczące CORS. Ponieważ nie skonfigurowano zasad domyślnych,app.UseCors()
sam nie włącza mechanizmu CORS.- Punkty
/echo
końcowe kontrolera i zezwalają na żądania między źródłami przy użyciu określonych zasad. - Punkty
/echo2
końcowe stron i Razor nie zezwalają na żądania między źródłami, ponieważ nie określono żadnych domyślnych zasad.
Atrybut [DisableCors] nie wyłącza mechanizmu CORS, który został włączony przez routing punktu końcowego za pomocą polecenia RequireCors
.
Aby uzyskać instrukcje dotyczące testowania kodu podobnego do poprzedniego, zobacz Testowanie mechanizmu CORS z routingiem punktu końcowego i [HttpOptions ].
Włączanie mechanizmu CORS z atrybutami
Włączenie mechanizmu CORS za pomocą atrybutu [EnableCors] i zastosowanie nazwanych zasad tylko do tych punktów końcowych, które wymagają mechanizmu CORS, zapewnia najlepszą kontrolę.
Atrybut [EnableCors] zapewnia alternatywę dla stosowania mechanizmu CORS globalnie. Atrybut [EnableCors]
umożliwia mechanizm CORS dla wybranych punktów końcowych, a nie wszystkich punktów końcowych:
[EnableCors]
określa zasady domyślne.[EnableCors("{Policy String}")]
określa nazwane zasady.
Atrybut [EnableCors]
można zastosować do:
- Razor Strona
PageModel
- Kontroler
- Metoda akcji kontrolera
Różne zasady można stosować do kontrolerów, modeli stron lub metod akcji za pomocą atrybutu [EnableCors]
. [EnableCors]
Gdy atrybut jest stosowany do kontrolera, modelu strony lub metody akcji, a mechanizm CORS jest włączony w programie pośredniczącym, stosowane są obie zasady. Zalecamy łączenie zasad. Użyj przycisku[EnableCors]
atrybutu lub oprogramowania pośredniczącego, a nie obu w tej samej aplikacji.
Poniższy kod stosuje inne zasady do każdej metody:
[Route("api/[controller]")]
[ApiController]
public class WidgetController : ControllerBase
{
// GET api/values
[EnableCors("AnotherPolicy")]
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "green widget", "red widget" };
}
// GET api/values/5
[EnableCors("Policy1")]
[HttpGet("{id}")]
public ActionResult<string> Get(int id)
{
return id switch
{
1 => "green widget",
2 => "red widget",
_ => NotFound(),
};
}
}
Poniższy kod tworzy dwie zasady CORS:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("Policy1",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
options.AddPolicy("AnotherPolicy",
policy =>
{
policy.WithOrigins("http://www.contoso.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
builder.Services.AddControllers();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.Run();
Aby uzyskać najlepszą kontrolę nad ograniczaniem żądań CORS:
- Użyj
[EnableCors("MyPolicy")]
z nazwanymi zasadami. - Nie należy definiować zasad domyślnych.
- Nie używaj routingu punktów końcowych.
Kod w następnej sekcji spełnia poprzednią listę.
Wyłączanie mechanizmu CORS
Atrybut [DisableCors] nie wyłącza mechanizmu CORS, który został włączony przez routing punktu końcowego.
Poniższy kod definiuje zasady "MyPolicy"
MECHANIZMU CORS:
var MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "MyPolicy",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com")
.WithMethods("PUT", "DELETE", "GET");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.MapRazorPages();
app.Run();
Poniższy kod wyłącza mechanizm CORS dla GetValues2
akcji:
[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public IActionResult Get() =>
ControllerContext.MyDisplayRouteInfo();
// GET api/values/5
[HttpGet("{id}")]
public IActionResult Get(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// PUT api/values/5
[HttpPut("{id}")]
public IActionResult Put(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// GET: api/values/GetValues2
[DisableCors]
[HttpGet("{action}")]
public IActionResult GetValues2() =>
ControllerContext.MyDisplayRouteInfo();
}
Powyższy kod ma następujące działanie:
- Nie włącza mechanizmu CORS z routingiem punktów końcowych.
- Nie definiuje domyślnych zasad CORS.
- Używa funkcji [EnableCors("MyPolicy")] w celu włączenia
"MyPolicy"
zasad CORS dla kontrolera. - Wyłącza mechanizm CORS dla
GetValues2
metody .
Aby uzyskać instrukcje dotyczące testowania poprzedniego kodu, zobacz Testowanie mechanizmu CORS .
Opcje zasad MECHANIZMU CORS
W tej sekcji opisano różne opcje, które można ustawić w zasadach MECHANIZMU CORS:
- Ustawianie dozwolonych źródeł
- Ustawianie dozwolonych metod HTTP
- Ustawianie dozwolonych nagłówków żądań
- Ustawianie uwidocznionych nagłówków odpowiedzi
- Poświadczenia w żądaniach między źródłami
- Ustawianie czasu wygaśnięcia przedlotu
AddPolicy jest wywoływana w pliku Program.cs
. W przypadku niektórych opcji warto zapoznać się z sekcją Jak działa mechanizm CORS.
Ustawianie dozwolonych źródeł
AllowAnyOrigin: zezwala na żądania CORS ze wszystkich źródeł przy użyciu dowolnego schematu (http
lub https
). AllowAnyOrigin
jest niezabezpieczona, ponieważ każda witryna internetowa może wysyłać żądania między źródłami do aplikacji.
Uwaga
Określanie AllowAnyOrigin
i AllowCredentials
jest niezabezpieczoną konfiguracją i może spowodować fałszerzowanie żądań między witrynami. Usługa CORS zwraca nieprawidłową odpowiedź CORS, gdy aplikacja jest skonfigurowana przy użyciu obu metod.
AllowAnyOrigin
dotyczy żądań wstępnych i nagłówka Access-Control-Allow-Origin
. Aby uzyskać więcej informacji, zobacz sekcję Wstępne żądania .
SetIsOriginAllowedToAllowWildcardSubdomains: Ustawia IsOriginAllowed właściwość zasad jako funkcję, która umożliwia źródłom dopasowanie skonfigurowanej domeny wieloznacznych podczas oceny, czy źródło jest dozwolone.
var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("https://*.example.com")
.SetIsOriginAllowedToAllowWildcardSubdomains();
});
});
builder.Services.AddControllers();
var app = builder.Build();
Ustawianie dozwolonych metod HTTP
- Zezwala na dowolną metodę HTTP:
- Wpływa na żądania wstępne i
Access-Control-Allow-Methods
nagłówek. Aby uzyskać więcej informacji, zobacz sekcję Wstępne żądania .
Ustawianie dozwolonych nagłówków żądań
Aby zezwolić na wysyłanie określonych nagłówków w żądaniu CORS, nazywanym nagłówkami żądań autora, wywołaj WithHeaders i określ dozwolone nagłówki:
using Microsoft.Net.Http.Headers;
var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com")
.WithHeaders(HeaderNames.ContentType, "x-custom-header");
});
});
builder.Services.AddControllers();
var app = builder.Build();
Aby zezwolić na wszystkie nagłówki żądań autora, wywołaj metodę AllowAnyHeader:
var MyAllowSpecificOrigins = "_MyAllowSubdomainPolicy";
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("https://*.example.com")
.AllowAnyHeader();
});
});
builder.Services.AddControllers();
var app = builder.Build();
AllowAnyHeader
dotyczy żądań wstępnych i nagłówka Access-Control-Request-Headers . Aby uzyskać więcej informacji, zobacz sekcję Wstępne żądania .
Zasady oprogramowania pośredniczącego CORS są zgodne z określonymi nagłówkami określonymi przez WithHeaders
usługę jest możliwe tylko wtedy, gdy nagłówki wysyłane w Access-Control-Request-Headers
formacie dokładnie odpowiadają nagłówkom określonym w elemencie WithHeaders
.
Rozważmy na przykład aplikację skonfigurowaną w następujący sposób:
app.UseCors(policy => policy.WithHeaders(HeaderNames.CacheControl));
Oprogramowanie pośredniczące CORS odrzuca żądanie wstępne z następującym nagłówkiem żądania, ponieważ Content-Language
(HeaderNames.ContentLanguage) nie ma na liście :WithHeaders
Access-Control-Request-Headers: Cache-Control, Content-Language
Aplikacja zwraca odpowiedź 200 OK , ale nie wysyła nagłówków CORS z powrotem. W związku z tym przeglądarka nie podejmuje próby żądania między źródłami.
Ustawianie uwidocznionych nagłówków odpowiedzi
Domyślnie przeglądarka nie ujawnia wszystkich nagłówków odpowiedzi aplikacji. Aby uzyskać więcej informacji, zobacz Udostępnianie zasobów między źródłami W3C (terminologia): prosty nagłówek odpowiedzi.
Nagłówki odpowiedzi, które są dostępne domyślnie, to:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
Specyfikacja MECHANIZMU CORS wywołuje te nagłówki prostych nagłówków odpowiedzi. Aby udostępnić inne nagłówki aplikacji, wywołaj metodę WithExposedHeaders:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyExposeResponseHeadersPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.WithExposedHeaders("x-custom-header");
});
});
builder.Services.AddControllers();
var app = builder.Build();
Poświadczenia w żądaniach między źródłami
Poświadczenia wymagają specjalnej obsługi w żądaniu CORS. Domyślnie przeglądarka nie wysyła poświadczeń z żądaniem między źródłami. Poświadczenia obejmują pliki cookie i schematy uwierzytelniania HTTP. Aby wysyłać poświadczenia z żądaniem między źródłami, klient musi ustawić wartość XMLHttpRequest.withCredentials
true
.
Bezpośrednie użycie XMLHttpRequest
:
var xhr = new XMLHttpRequest();
xhr.open('get', 'https://www.example.com/api/test');
xhr.withCredentials = true;
Korzystanie z zapytania jQuery:
$.ajax({
type: 'get',
url: 'https://www.example.com/api/test',
xhrFields: {
withCredentials: true
}
});
Korzystanie z interfejsu API pobierania:
fetch('https://www.example.com/api/test', {
credentials: 'include'
});
Serwer musi zezwalać na poświadczenia. Aby zezwolić na poświadczenia między źródłami, wywołaj metodę AllowCredentials:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyMyAllowCredentialsPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.AllowCredentials();
});
});
builder.Services.AddControllers();
var app = builder.Build();
Odpowiedź HTTP zawiera Access-Control-Allow-Credentials
nagłówek, który informuje przeglądarkę, że serwer zezwala na poświadczenia dla żądania między źródłami.
Jeśli przeglądarka wysyła poświadczenia, ale odpowiedź nie zawiera prawidłowego Access-Control-Allow-Credentials
nagłówka, przeglądarka nie uwidacznia odpowiedzi na aplikację, a żądanie między źródłami zakończy się niepowodzeniem.
Zezwolenie na poświadczenia między źródłami jest zagrożeniem bezpieczeństwa. Witryna internetowa w innej domenie może wysyłać poświadczenia zalogowanego użytkownika do aplikacji w imieniu użytkownika bez wiedzy użytkownika.
Specyfikacja MECHANIZMU CORS stwierdza również, że ustawienie wartości origins na "*"
(wszystkie źródła) jest nieprawidłowe, jeśli Access-Control-Allow-Credentials
nagłówek jest obecny.
Żądania wstępne
W przypadku niektórych żądań CORS przeglądarka wysyła dodatkowe żądanie OPTIONS przed wysłaniem rzeczywistego żądania. To żądanie jest nazywane żądaniem wstępnym. Przeglądarka może pominąć żądanie wstępne, jeśli spełnione są wszystkie następujące warunki:
- Metoda żądania to GET, HEAD lub POST.
- Aplikacja nie ustawia nagłówków żądań innych niż
Accept
, ,Accept-Language
,Content-Language
,Content-Type
lubLast-Event-ID
. - Nagłówek
Content-Type
, jeśli jest ustawiony, ma jedną z następujących wartości:application/x-www-form-urlencoded
multipart/form-data
text/plain
Reguła nagłówków żądań ustawiona dla żądania klienta ma zastosowanie do nagłówków ustawianych przez aplikację przez wywołanie setRequestHeader
XMLHttpRequest
obiektu. Specyfikacja MECHANIZMU CORS wywołuje te nagłówki żądań autora. Reguła nie ma zastosowania do nagłówków, które można ustawić w przeglądarce, takich jak User-Agent
, Host
lub Content-Length
.
Poniżej przedstawiono przykładową odpowiedź podobną do żądania wstępnego wykonanego z przycisku [Put test] w sekcji Test CORS tego dokumentu.
General:
Request URL: https://cors3.azurewebsites.net/api/values/5
Request Method: OPTIONS
Status Code: 204 No Content
Response Headers:
Access-Control-Allow-Methods: PUT,DELETE,GET
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f8...8;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Vary: Origin
Request Headers:
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Method: PUT
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0
Żądanie wstępne używa metody HTTP OPTIONS . Może zawierać następujące nagłówki:
- Access-Control-Request-Method: metoda HTTP, która będzie używana dla rzeczywistego żądania.
- Access-Control-Request-Headers: lista nagłówków żądań ustawianych przez aplikację w rzeczywistym żądaniu. Jak wspomniano wcześniej, nie zawiera to nagłówków ustawionych przez przeglądarkę, takich jak
User-Agent
. - Access-Control-Allow-Methods
Jeśli żądanie wstępne zostanie odrzucone, aplikacja zwróci 200 OK
odpowiedź, ale nie ustawi nagłówków CORS. W związku z tym przeglądarka nie podejmuje próby żądania między źródłami. Aby zapoznać się z przykładem odmowy żądania wstępnego, zobacz sekcję Test CORS tego dokumentu.
Za pomocą narzędzi F12 aplikacja konsolowa wyświetla błąd podobny do jednego z następujących, w zależności od przeglądarki:
- Firefox: Żądanie między źródłami zablokowane: Te same zasady pochodzenia nie zezwalają na odczytywanie zasobu zdalnego pod adresem
https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5
. (Przyczyna: żądanie CORS nie powiodło się). Dowiedz się więcej - Oparty na chromium: dostęp do pobierania z źródła "https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5https://cors3.azurewebsites.net" został zablokowany przez zasady CORS: Odpowiedź na żądanie wstępne nie przekazuje kontroli dostępu: Brak nagłówka "Access-Control-Allow-Origin" dla żądanego zasobu. Jeśli nieprzezroczysta odpowiedź spełnia Twoje potrzeby, ustaw tryb żądania na wartość "no-cors", aby pobrać zasób z wyłączonym mechanizmem CORS.
Aby zezwolić na określone nagłówki, wywołaj metodę WithHeaders:
using Microsoft.Net.Http.Headers;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyAllowHeadersPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.WithHeaders(HeaderNames.ContentType, "x-custom-header");
});
});
builder.Services.AddControllers();
var app = builder.Build();
Aby zezwolić na wszystkie nagłówki żądań autora, wywołaj metodę AllowAnyHeader:
using Microsoft.Net.Http.Headers;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MyAllowAllHeadersPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.AllowAnyHeader();
});
});
builder.Services.AddControllers();
var app = builder.Build();
Przeglądarki nie są spójne w sposobie ustawiania .Access-Control-Request-Headers
Jeśli:
- Nagłówki są ustawione na inne niż
"*"
- AllowAnyHeader jest wywoływany: uwzględnij co najmniej
Accept
,Content-Type
iOrigin
, oraz wszelkie nagłówki niestandardowe, które mają być obsługiwane.
Kod automatycznego żądania wstępnego
Po zastosowaniu zasad CORS:
- Globalnie przez wywołanie metody
app.UseCors
w plikuProgram.cs
. - Za pomocą atrybutu
[EnableCors]
.
ASP.NET Core odpowiada na żądanie OPCJE wstępne.
Włączenie mechanizmu CORS dla poszczególnych punktów końcowych przy użyciu RequireCors
obecnie nie obsługuje automatycznych żądań wstępnych.
W sekcji Test CORS tego dokumentu pokazano to zachowanie.
[HttpOptions] atrybut dla żądań wstępnych
Gdy mechanizm CORS jest włączony z odpowiednimi zasadami, ASP.NET Core zwykle odpowiada na żądania wstępne CORS. W niektórych scenariuszach może to nie być możliwe. Na przykład użycie mechanizmu CORS z routingiem punktów końcowych.
Poniższy kod używa atrybutu [HttpOptions] do tworzenia punktów końcowych dla żądań OPTIONS:
[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
// OPTIONS: api/TodoItems2/5
[HttpOptions("{id}")]
public IActionResult PreflightRoute(int id)
{
return NoContent();
}
// OPTIONS: api/TodoItems2
[HttpOptions]
public IActionResult PreflightRoute()
{
return NoContent();
}
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id)
{
if (id < 1)
{
return BadRequest();
}
return ControllerContext.MyDisplayRouteInfo(id);
}
Aby uzyskać instrukcje dotyczące testowania poprzedniego kodu, zobacz Testowanie mechanizmu CORS przy użyciu routingu punktu końcowego i [HttpOptions ].
Ustawianie czasu wygaśnięcia przedlotu
Nagłówek Access-Control-Max-Age
określa, jak długo można buforować odpowiedź na żądanie wstępne. Aby ustawić ten nagłówek, wywołaj metodę SetPreflightMaxAge:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy("MySetPreflightExpirationPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.SetPreflightMaxAge(TimeSpan.FromSeconds(2520));
});
});
builder.Services.AddControllers();
var app = builder.Build();
Jak działa mechanizm CORS
W tej sekcji opisano, co dzieje się w żądaniu CORS na poziomie komunikatów HTTP.
- MECHANIZM CORS nie jest funkcją zabezpieczeń. CORS to standard W3C, który umożliwia serwerowi złagodzenie zasad tego samego źródła.
- Na przykład złośliwy aktor może użyć skryptów między witrynami (XSS) w witrynie i wykonać żądanie obejmujące wiele witryn do witryny obsługującej mechanizm CORS w celu kradzieży informacji.
- Interfejs API nie jest bezpieczniejszy, zezwalając na mechanizm CORS.
- Do klienta (przeglądarki) należy wymuszenie mechanizmu CORS. Serwer wykonuje żądanie i zwraca odpowiedź— klient zwraca błąd i blokuje odpowiedź. Na przykład dowolne z następujących narzędzi wyświetli odpowiedź serwera:
- Fiddler
- .NET HttpClient
- Przeglądarka internetowa, wprowadzając adres URL na pasku adresu.
- Do klienta (przeglądarki) należy wymuszenie mechanizmu CORS. Serwer wykonuje żądanie i zwraca odpowiedź— klient zwraca błąd i blokuje odpowiedź. Na przykład dowolne z następujących narzędzi wyświetli odpowiedź serwera:
- Jest to sposób na serwer, aby umożliwić przeglądarkom wykonywanie między źródłami żądania XHR lub Fetch API , które w przeciwnym razie byłoby zabronione.
- Przeglądarki bez mechanizmu CORS nie mogą wykonywać żądań między źródłami. Przed mechanizmem CORS kod JSONP został użyty do obejścia tego ograniczenia. JSONP nie używa XHR, używa tagu
<script>
do odbierania odpowiedzi. Skrypty mogą być ładowane między źródłami.
- Przeglądarki bez mechanizmu CORS nie mogą wykonywać żądań między źródłami. Przed mechanizmem CORS kod JSONP został użyty do obejścia tego ograniczenia. JSONP nie używa XHR, używa tagu
Specyfikacja MECHANIZMU CORS wprowadziła kilka nowych nagłówków HTTP, które umożliwiają żądania między źródłami. Jeśli przeglądarka obsługuje mechanizm CORS, automatycznie ustawia te nagłówki dla żądań między źródłami. Niestandardowy kod JavaScript nie jest wymagany do włączenia mechanizmu CORS.
Poniżej przedstawiono przykład żądania między źródłami z przycisku Test wartości do https://cors1.azurewebsites.net/api/values
. Nagłówek Origin
:
- Udostępnia domenę lokacji wysyłającej żądanie.
- Jest wymagany i musi być inny niż host.
Nagłówki ogólne
Request URL: https://cors1.azurewebsites.net/api/values
Request Method: GET
Status Code: 200 OK
Nagłówki odpowiedzi
Content-Encoding: gzip
Content-Type: text/plain; charset=utf-8
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Transfer-Encoding: chunked
Vary: Accept-Encoding
X-Powered-By: ASP.NET
Nagłówki żądań
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Host: cors1.azurewebsites.net
Origin: https://cors3.azurewebsites.net
Referer: https://cors3.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 ...
W OPTIONS
żądaniach serwer ustawia nagłówek Nagłówki Access-Control-Allow-Origin: {allowed origin}
odpowiedzi w odpowiedzi. Na przykład wdrożone przykładowe żądanie przycisku OPTIONS
Usuń [EnableCors] zawiera następujące nagłówki:
Nagłówki ogólne
Request URL: https://cors3.azurewebsites.net/api/TodoItems2/MyDelete2/5
Request Method: OPTIONS
Status Code: 204 No Content
Nagłówki odpowiedzi
Access-Control-Allow-Headers: Content-Type,x-custom-header
Access-Control-Allow-Methods: PUT,DELETE,GET,OPTIONS
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors3.azurewebsites.net
Vary: Origin
X-Powered-By: ASP.NET
Nagłówki żądań
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: DELETE
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/test?number=2
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0
W poprzednich nagłówkach Odpowiedzi serwer ustawia nagłówek Access-Control-Allow-Origin w odpowiedzi. Wartość https://cors1.azurewebsites.net
tego nagłówka odpowiada nagłówkowi Origin
z żądania.
Jeśli AllowAnyOrigin parametr jest wywoływany, zwracana jest wartość z symbolem Access-Control-Allow-Origin: *
wieloznacznymi. AllowAnyOrigin
zezwala na dowolne źródło.
Jeśli odpowiedź nie zawiera nagłówka Access-Control-Allow-Origin
, żądanie między źródłami zakończy się niepowodzeniem. W szczególności przeglądarka nie zezwala na żądanie. Nawet jeśli serwer zwróci pomyślną odpowiedź, przeglądarka nie udostępni odpowiedzi aplikacji klienckiej.
Przekierowanie HTTP do protokołu HTTPS powoduje ERR_INVALID_REDIRECT w żądaniu wstępnym CORS
Żądania do punktu końcowego przy użyciu protokołu HTTP, które są przekierowywane do protokołu HTTPS przez UseHttpsRedirection niepowodzenie z .ERR_INVALID_REDIRECT on the CORS preflight request
Projekty interfejsu API mogą odrzucać żądania HTTP, a nie przekierowywać UseHttpsRedirection
żądania do protokołu HTTPS.
Wyświetlanie żądań OPTIONS
Domyślnie przeglądarki Chrome i Edge nie wyświetlają żądań OPTIONS na karcie sieci narzędzi F12. Aby wyświetlić żądania OPTIONS w następujących przeglądarkach:
chrome://flags/#out-of-blink-cors
lubedge://flags/#out-of-blink-cors
- wyłącz flagę.
- restart.
Przeglądarka Firefox domyślnie wyświetla żądania OPTIONS.
Mechanizm CORS w usługach IIS
Podczas wdrażania w usługach IIS mechanizm CORS musi działać przed uwierzytelnianiem systemu Windows, jeśli serwer nie jest skonfigurowany do zezwalania na dostęp anonimowy. Aby obsługiwać ten scenariusz, moduł CORS usług IIS musi zostać zainstalowany i skonfigurowany dla aplikacji.
Testowanie mechanizmu CORS
Przykładowy plik do pobrania zawiera kod do testowania mechanizmu CORS. Zobacz , jak pobrać. Przykład jest projektem interfejsu API z dodanymi stronami Razor :
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "MyPolicy",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com",
"https://cors1.azurewebsites.net",
"https://cors3.azurewebsites.net",
"https://localhost:44398",
"https://localhost:5001")
.WithMethods("PUT", "DELETE", "GET");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.MapRazorPages();
app.Run();
Ostrzeżenie
WithOrigins("https://localhost:<port>");
należy używać tylko do testowania przykładowej aplikacji podobnej do przykładowego kodu pobierania.
Poniżej przedstawiono ValuesController
punkty końcowe do testowania:
[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public IActionResult Get() =>
ControllerContext.MyDisplayRouteInfo();
// GET api/values/5
[HttpGet("{id}")]
public IActionResult Get(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// PUT api/values/5
[HttpPut("{id}")]
public IActionResult Put(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// GET: api/values/GetValues2
[DisableCors]
[HttpGet("{action}")]
public IActionResult GetValues2() =>
ControllerContext.MyDisplayRouteInfo();
}
MyDisplayRouteInfo jest dostarczany przez pakiet NuGet Rick.Docs.Samples.RouteInfo i wyświetla informacje o trasie.
Przetestuj poprzedni przykładowy kod przy użyciu jednego z następujących metod:
- Uruchom przykład przy
dotnet run
użyciu domyślnego adresu URL .https://localhost:5001
- Uruchom przykład z programu Visual Studio z portem ustawionym na 44398 jako adres URL
https://localhost:44398
.
Za pomocą przeglądarki z narzędziami F12:
Wybierz przycisk Wartości i przejrzyj nagłówki na karcie Sieć.
Wybierz przycisk TEST PUT. Zobacz Wyświetlanie żądań OPTIONS, aby uzyskać instrukcje dotyczące wyświetlania żądania OPTIONS. Test PUT tworzy dwa żądania, żądanie wstępne OPTIONS i żądanie PUT.
Wybierz przycisk,
GetValues2 [DisableCors]
aby wyzwolić nieudane żądanie CORS. Jak wspomniano w dokumencie, odpowiedź zwraca 200 powodzenia, ale żądanie CORS nie jest wykonywane. Wybierz kartę Konsola, aby wyświetlić błąd CORS. W zależności od przeglądarki zostanie wyświetlony błąd podobny do następującego:Dostęp do pobierania
'https://cors1.azurewebsites.net/api/values/GetValues2'
z źródła'https://cors3.azurewebsites.net'
został zablokowany przez zasady CORS: w żądanym zasobie nie ma nagłówka "Access-Control-Allow-Origin". Jeśli nieprzezroczysta odpowiedź spełnia Twoje potrzeby, ustaw tryb żądania na wartość "no-cors", aby pobrać zasób z wyłączonym mechanizmem CORS.
Punkty końcowe z obsługą mechanizmu CORS można przetestować za pomocą narzędzia, takiego jak curl lub Fiddler. W przypadku korzystania z narzędzia źródło żądania określonego przez Origin
nagłówek musi się różnić od hosta odbierającego żądanie. Jeśli żądanie nie jest źródłem krzyżowym na podstawie wartości nagłówka Origin
:
- Nie ma potrzeby przetwarzania żądania przez oprogramowanie pośredniczące CORS.
- Nagłówki CORS nie są zwracane w odpowiedzi.
Następujące polecenie używa curl
polecenia , aby wysłać żądanie OPTIONS z informacjami:
curl -X OPTIONS https://cors3.azurewebsites.net/api/TodoItems2/5 -i
Testowanie mechanizmu CORS przy użyciu routingu punktu końcowego i [HttpOptions]
Włączenie mechanizmu CORS dla poszczególnych punktów końcowych przy użyciu RequireCors
obecnie nie obsługuje automatycznych żądań wstępnych. Rozważmy następujący kod, który używa routingu punktu końcowego w celu włączenia mechanizmu CORS:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddCors(options =>
{
options.AddPolicy(name: "MyPolicy",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com",
"https://cors1.azurewebsites.net",
"https://cors3.azurewebsites.net",
"https://localhost:44398",
"https://localhost:5001")
.WithMethods("PUT", "DELETE", "GET");
});
});
builder.Services.AddControllers();
builder.Services.AddRazorPages();
var app = builder.Build();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.MapControllers();
app.MapRazorPages();
app.Run();
Poniżej przedstawiono TodoItems1Controller
punkty końcowe do testowania:
[Route("api/[controller]")]
[ApiController]
public class TodoItems1Controller : ControllerBase
{
// PUT: api/TodoItems1/5
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id)
{
if (id < 1)
{
return Content($"ID = {id}");
}
return ControllerContext.MyDisplayRouteInfo(id);
}
// Delete: api/TodoItems1/5
[HttpDelete("{id}")]
public IActionResult MyDelete(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// GET: api/TodoItems1
[HttpGet]
public IActionResult GetTodoItems() =>
ControllerContext.MyDisplayRouteInfo();
[EnableCors]
[HttpGet("{action}")]
public IActionResult GetTodoItems2() =>
ControllerContext.MyDisplayRouteInfo();
// Delete: api/TodoItems1/MyDelete2/5
[EnableCors]
[HttpDelete("{action}/{id}")]
public IActionResult MyDelete2(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
}
Przetestuj powyższy kod ze strony testowej (https://cors1.azurewebsites.net/test?number=1
) wdrożonego przykładu.
Przyciski Usuń [EnableCors] i GET [EnableCors] kończą się powodzeniem, ponieważ punkty końcowe mają [EnableCors]
żądania wstępne i odpowiadają na nie. Inne punkty końcowe kończą się niepowodzeniem. Przycisk GET kończy się niepowodzeniem, ponieważ skrypt JavaScript wysyła:
headers: {
"Content-Type": "x-custom-header"
},
Poniższe informacje TodoItems2Controller
zawierają podobne punkty końcowe, ale zawierają jawny kod, który odpowiada na żądania OPTIONS:
[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
// OPTIONS: api/TodoItems2/5
[HttpOptions("{id}")]
public IActionResult PreflightRoute(int id)
{
return NoContent();
}
// OPTIONS: api/TodoItems2
[HttpOptions]
public IActionResult PreflightRoute()
{
return NoContent();
}
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id)
{
if (id < 1)
{
return BadRequest();
}
return ControllerContext.MyDisplayRouteInfo(id);
}
// [EnableCors] // Not needed as OPTIONS path provided
[HttpDelete("{id}")]
public IActionResult MyDelete(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
[EnableCors] // Rquired for this path
[HttpGet]
public IActionResult GetTodoItems() =>
ControllerContext.MyDisplayRouteInfo();
[HttpGet("{action}")]
public IActionResult GetTodoItems2() =>
ControllerContext.MyDisplayRouteInfo();
[EnableCors] // Rquired for this path
[HttpDelete("{action}/{id}")]
public IActionResult MyDelete2(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
}
Powyższy kod można przetestować, wdrażając przykład w celu Azure.In listy rozwijanej Kontroler, wybierz pozycję Wstępne, a następnie ustaw kontroler. Wszystkie wywołania CORS do punktów końcowych kończą się powodzeniem TodoItems2Controller
.
Dodatkowe zasoby
Autorzy: Rick Anderson i Kirk Larkin
W tym artykule pokazano, jak włączyć mechanizm CORS w aplikacji ASP.NET Core.
Zabezpieczenia przeglądarki uniemożliwiają stronie internetowej wykonywanie żądań do innej domeny niż ta, która obsłużyła stronę internetową. To ograniczenie określa się jako zasadę tego samego źródła. Zasada tego samego źródła uniemożliwia złośliwym witrynom odczytywanie poufnych danych z innej witryny. Czasami możesz zezwolić innym witrynom na wykonywanie żądań w aplikacji o innym źródle. Aby uzyskać więcej informacji, zobacz artykuł Mozilla CORS.
Współużytkowanie zasobów między źródłami (CORS):
- Jest standardem W3C, który umożliwia serwerowi złagodzenie zasad tego samego źródła.
- Nie jest funkcją zabezpieczeń, mechanizm CORS zrelaksuje zabezpieczenia. Interfejs API nie jest bezpieczniejszy, zezwalając na mechanizm CORS. Aby uzyskać więcej informacji, zobacz Jak działa mechanizm CORS.
- Zezwala serwerowi na jawne zezwalanie na niektóre żądania między źródłami podczas odrzucania innych.
- Jest bezpieczniejszy i bardziej elastyczny niż wcześniejsze techniki, takie jak JSONP.
Wyświetl lub pobierz przykładowy kod (jak pobrać)
To samo źródło
Dwa adresy URL mają to samo źródło, jeśli mają identyczne schematy, hosty i porty (RFC 6454).
Te dwa adresy URL mają to samo źródło:
https://example.com/foo.html
https://example.com/bar.html
Te adresy URL mają inne źródła niż poprzednie dwa adresy URL:
https://example.net
: Inna domenahttps://www.example.com/foo.html
: Inna poddomenahttp://example.com/foo.html
: Inny schemathttps://example.com:9000/foo.html
: Inny port
Włączanie mechanizmu CORS
Istnieją trzy sposoby włączania mechanizmu CORS:
- W przypadku oprogramowania pośredniczącego przy użyciu nazwanych zasad lub zasad domyślnych.
- Korzystanie z routingu punktów końcowych.
- Za pomocą atrybutu [EnableCors].
Użycie atrybutu [EnableCors] z nazwanymi zasadami zapewnia najlepszą kontrolę w ograniczaniu punktów końcowych obsługujących mechanizm CORS.
Ostrzeżenie
UseCors musi być wywoływana w odpowiedniej kolejności. Aby uzyskać więcej informacji, zobacz Kolejność oprogramowania pośredniczącego. Na przykład UseCors
należy wywołać metodę przed UseResponseCaching użyciem polecenia UseResponseCaching
.
Każde podejście zostało szczegółowo opisane w poniższych sekcjach.
MECHANIZM CORS z nazwanymi zasadami i oprogramowaniem pośredniczącym
Oprogramowanie pośredniczące CORS obsługuje żądania między źródłami. Poniższy kod stosuje zasady CORS do wszystkich punktów końcowych aplikacji z określonymi źródłami:
public class Startup
{
readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
// services.AddResponseCaching();
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors(MyAllowSpecificOrigins);
// app.UseResponseCaching();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
Powyższy kod ma następujące działanie:
- Ustawia nazwę zasad na
_myAllowSpecificOrigins
. Nazwa zasad jest dowolna. - Wywołuje metodę UseCors rozszerzenia i określa
_myAllowSpecificOrigins
zasady CORS.UseCors
dodaje oprogramowanie pośredniczące CORS. WywołanieUseCors
musi zostać umieszczone poUseRouting
metodzie , ale przedUseAuthorization
. Aby uzyskać więcej informacji, zobacz Kolejność oprogramowania pośredniczącego. - Wywołania AddCors za pomocą wyrażenia lambda. Lambda przyjmuje CorsPolicyBuilder obiekt. Opcje konfiguracji, takie jak
WithOrigins
, zostały opisane w dalszej części tego artykułu. _myAllowSpecificOrigins
Włącza zasady CORS dla wszystkich punktów końcowych kontrolera. Zobacz Routing punktów końcowych, aby zastosować zasady CORS do określonych punktów końcowych.- W przypadku korzystania z oprogramowania pośredniczącego buforowania odpowiedzi wywołaj metodę UseCors przed UseResponseCaching.
W przypadku routingu punktów końcowych oprogramowanie pośredniczące CORS musi być skonfigurowane do wykonywania między wywołaniami do UseRouting
i UseEndpoints
.
Zobacz Testowanie mechanizmu CORS , aby uzyskać instrukcje dotyczące testowania kodu podobnego do poprzedniego kodu.
Wywołanie AddCors metody dodaje usługi CORS do kontenera usługi aplikacji:
public class Startup
{
readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
// services.AddResponseCaching();
services.AddControllers();
}
Aby uzyskać więcej informacji, zobacz opcje zasad MECHANIZMU CORS w tym dokumencie.
CorsPolicyBuilder Metody można połączyć łańcuchem, jak pokazano w poniższym kodzie:
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
services.AddControllers();
}
Uwaga: określony adres URL nie może zawierać ukośnika końcowego (/
). Jeśli adres URL zakończy się ciągiem /
, porównanie zwróci wartość false
i nie zostanie zwrócony żaden nagłówek.
MECHANIZM CORS z domyślnymi zasadami i oprogramowaniem pośredniczącym
Poniższy wyróżniony kod włącza domyślne zasady MECHANIZMU CORS:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddDefaultPolicy(
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
Powyższy kod stosuje domyślne zasady CORS do wszystkich punktów końcowych kontrolera.
Włączanie mechanizmu Cors z routingiem punktów końcowych
Włączenie mechanizmu CORS dla poszczególnych punktów końcowych przy użyciu RequireCors
nie obsługuje automatycznych żądań wstępnych. Aby uzyskać więcej informacji, zobacz ten problem z usługą GitHub i Przetestuj mechanizm CORS z routingiem punktów końcowych i [HttpOptions].
W przypadku routingu punktu końcowego mechanizm CORS można włączyć dla poszczególnych punktów końcowych przy użyciu RequireCors zestawu metod rozszerzeń:
public class Startup
{
readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins";
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(name: MyAllowSpecificOrigins,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
});
services.AddControllers();
services.AddRazorPages();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/echo",
context => context.Response.WriteAsync("echo"))
.RequireCors(MyAllowSpecificOrigins);
endpoints.MapControllers()
.RequireCors(MyAllowSpecificOrigins);
endpoints.MapGet("/echo2",
context => context.Response.WriteAsync("echo2"));
endpoints.MapRazorPages();
});
}
}
Powyższy kod:
app.UseCors
włącza oprogramowanie pośredniczące CORS. Ponieważ nie skonfigurowano zasad domyślnych,app.UseCors()
sam nie włącza mechanizmu CORS.- Punkty
/echo
końcowe kontrolera i zezwalają na żądania między źródłami przy użyciu określonych zasad. - Punkty
/echo2
końcowe stron i Razor nie zezwalają na żądania między źródłami, ponieważ nie określono żadnych domyślnych zasad.
Atrybut [DisableCors] nie wyłącza mechanizmu CORS, który został włączony przez routing punktu końcowego za pomocą polecenia RequireCors
.
Aby uzyskać instrukcje dotyczące testowania kodu podobnego do poprzedniego, zobacz Testowanie mechanizmu CORS z routingiem punktu końcowego i [HttpOptions ].
Włączanie mechanizmu CORS z atrybutami
Włączenie mechanizmu CORS za pomocą atrybutu [EnableCors] i zastosowanie nazwanych zasad tylko do tych punktów końcowych, które wymagają mechanizmu CORS, zapewnia najlepszą kontrolę.
Atrybut [EnableCors] zapewnia alternatywę dla stosowania mechanizmu CORS globalnie. Atrybut [EnableCors]
umożliwia mechanizm CORS dla wybranych punktów końcowych, a nie wszystkich punktów końcowych:
[EnableCors]
określa zasady domyślne.[EnableCors("{Policy String}")]
określa nazwane zasady.
Atrybut [EnableCors]
można zastosować do:
- Razor Strona
PageModel
- Kontroler
- Metoda akcji kontrolera
Różne zasady można stosować do kontrolerów, modeli stron lub metod akcji za pomocą atrybutu [EnableCors]
. [EnableCors]
Gdy atrybut jest stosowany do kontrolera, modelu strony lub metody akcji, a mechanizm CORS jest włączony w programie pośredniczącym, stosowane są obie zasady. Zalecamy łączenie zasad. Użyj przycisku[EnableCors]
atrybutu lub oprogramowania pośredniczącego, a nie obu w tej samej aplikacji.
Poniższy kod stosuje inne zasady do każdej metody:
[Route("api/[controller]")]
[ApiController]
public class WidgetController : ControllerBase
{
// GET api/values
[EnableCors("AnotherPolicy")]
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
return new string[] { "green widget", "red widget" };
}
// GET api/values/5
[EnableCors("Policy1")]
[HttpGet("{id}")]
public ActionResult<string> Get(int id)
{
return id switch
{
1 => "green widget",
2 => "red widget",
_ => NotFound(),
};
}
}
Poniższy kod tworzy dwie zasady CORS:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy("Policy1",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com");
});
options.AddPolicy("AnotherPolicy",
policy =>
{
policy.WithOrigins("http://www.contoso.com")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
Aby uzyskać najlepszą kontrolę nad ograniczaniem żądań CORS:
- Użyj
[EnableCors("MyPolicy")]
z nazwanymi zasadami. - Nie należy definiować zasad domyślnych.
- Nie używaj routingu punktów końcowych.
Kod w następnej sekcji spełnia poprzednią listę.
Zobacz Testowanie mechanizmu CORS , aby uzyskać instrukcje dotyczące testowania kodu podobnego do poprzedniego kodu.
Wyłączanie mechanizmu CORS
Atrybut [DisableCors] nie wyłącza mechanizmu CORS, który został włączony przez routing punktu końcowego.
Poniższy kod definiuje zasady "MyPolicy"
MECHANIZMU CORS:
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(name: "MyPolicy",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com")
.WithMethods("PUT", "DELETE", "GET");
});
});
services.AddControllers();
services.AddRazorPages();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapRazorPages();
});
}
}
Poniższy kod wyłącza mechanizm CORS dla GetValues2
akcji:
[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public IActionResult Get() =>
ControllerContext.MyDisplayRouteInfo();
// GET api/values/5
[HttpGet("{id}")]
public IActionResult Get(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// PUT api/values/5
[HttpPut("{id}")]
public IActionResult Put(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// GET: api/values/GetValues2
[DisableCors]
[HttpGet("{action}")]
public IActionResult GetValues2() =>
ControllerContext.MyDisplayRouteInfo();
}
Powyższy kod ma następujące działanie:
- Nie włącza mechanizmu CORS z routingiem punktów końcowych.
- Nie definiuje domyślnych zasad CORS.
- Używa funkcji [EnableCors("MyPolicy")] w celu włączenia
"MyPolicy"
zasad CORS dla kontrolera. - Wyłącza mechanizm CORS dla
GetValues2
metody .
Aby uzyskać instrukcje dotyczące testowania poprzedniego kodu, zobacz Testowanie mechanizmu CORS .
Opcje zasad MECHANIZMU CORS
W tej sekcji opisano różne opcje, które można ustawić w zasadach MECHANIZMU CORS:
- Ustawianie dozwolonych źródeł
- Ustawianie dozwolonych metod HTTP
- Ustawianie dozwolonych nagłówków żądań
- Ustawianie uwidocznionych nagłówków odpowiedzi
- Poświadczenia w żądaniach między źródłami
- Ustawianie czasu wygaśnięcia przedlotu
AddPolicy jest wywoływana w pliku Startup.ConfigureServices
. W przypadku niektórych opcji warto zapoznać się z sekcją Jak działa mechanizm CORS.
Ustawianie dozwolonych źródeł
AllowAnyOrigin: zezwala na żądania CORS ze wszystkich źródeł przy użyciu dowolnego schematu (http
lub https
). AllowAnyOrigin
jest niezabezpieczona, ponieważ każda witryna internetowa może wysyłać żądania między źródłami do aplikacji.
Uwaga
Określanie AllowAnyOrigin
i AllowCredentials
jest niezabezpieczoną konfiguracją i może spowodować fałszerzowanie żądań między witrynami. Usługa CORS zwraca nieprawidłową odpowiedź CORS, gdy aplikacja jest skonfigurowana przy użyciu obu metod.
AllowAnyOrigin
dotyczy żądań wstępnych i nagłówka Access-Control-Allow-Origin
. Aby uzyskać więcej informacji, zobacz sekcję Wstępne żądania .
SetIsOriginAllowedToAllowWildcardSubdomains: Ustawia IsOriginAllowed właściwość zasad jako funkcję, która umożliwia źródłom dopasowanie skonfigurowanej domeny wieloznacznych podczas oceny, czy źródło jest dozwolone.
options.AddPolicy("MyAllowSubdomainPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.SetIsOriginAllowedToAllowWildcardSubdomains();
});
Ustawianie dozwolonych metod HTTP
- Zezwala na dowolną metodę HTTP:
- Wpływa na żądania wstępne i
Access-Control-Allow-Methods
nagłówek. Aby uzyskać więcej informacji, zobacz sekcję Wstępne żądania .
Ustawianie dozwolonych nagłówków żądań
Aby zezwolić na wysyłanie określonych nagłówków w żądaniu CORS, nazywanym nagłówkami żądań autora, wywołaj WithHeaders i określ dozwolone nagłówki:
options.AddPolicy("MyAllowHeadersPolicy",
policy =>
{
// requires using Microsoft.Net.Http.Headers;
policy.WithOrigins("http://example.com")
.WithHeaders(HeaderNames.ContentType, "x-custom-header");
});
Aby zezwolić na wszystkie nagłówki żądań autora, wywołaj metodę AllowAnyHeader:
options.AddPolicy("MyAllowAllHeadersPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.AllowAnyHeader();
});
AllowAnyHeader
dotyczy żądań wstępnych i nagłówka Access-Control-Request-Headers . Aby uzyskać więcej informacji, zobacz sekcję Wstępne żądania .
Zasady oprogramowania pośredniczącego CORS są zgodne z określonymi nagłówkami określonymi przez WithHeaders
usługę jest możliwe tylko wtedy, gdy nagłówki wysyłane w Access-Control-Request-Headers
formacie dokładnie odpowiadają nagłówkom określonym w elemencie WithHeaders
.
Rozważmy na przykład aplikację skonfigurowaną w następujący sposób:
app.UseCors(policy => policy.WithHeaders(HeaderNames.CacheControl));
Oprogramowanie pośredniczące CORS odrzuca żądanie wstępne z następującym nagłówkiem żądania, ponieważ Content-Language
(HeaderNames.ContentLanguage) nie ma na liście :WithHeaders
Access-Control-Request-Headers: Cache-Control, Content-Language
Aplikacja zwraca odpowiedź 200 OK , ale nie wysyła nagłówków CORS z powrotem. W związku z tym przeglądarka nie podejmuje próby żądania między źródłami.
Ustawianie uwidocznionych nagłówków odpowiedzi
Domyślnie przeglądarka nie ujawnia wszystkich nagłówków odpowiedzi aplikacji. Aby uzyskać więcej informacji, zobacz Udostępnianie zasobów między źródłami W3C (terminologia): prosty nagłówek odpowiedzi.
Nagłówki odpowiedzi, które są dostępne domyślnie, to:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
Specyfikacja MECHANIZMU CORS wywołuje te nagłówki prostych nagłówków odpowiedzi. Aby udostępnić inne nagłówki aplikacji, wywołaj metodę WithExposedHeaders:
options.AddPolicy("MyExposeResponseHeadersPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.WithExposedHeaders("x-custom-header");
});
Poświadczenia w żądaniach między źródłami
Poświadczenia wymagają specjalnej obsługi w żądaniu CORS. Domyślnie przeglądarka nie wysyła poświadczeń z żądaniem między źródłami. Poświadczenia obejmują pliki cookie i schematy uwierzytelniania HTTP. Aby wysyłać poświadczenia z żądaniem między źródłami, klient musi ustawić wartość XMLHttpRequest.withCredentials
true
.
Bezpośrednie użycie XMLHttpRequest
:
var xhr = new XMLHttpRequest();
xhr.open('get', 'https://www.example.com/api/test');
xhr.withCredentials = true;
Korzystanie z zapytania jQuery:
$.ajax({
type: 'get',
url: 'https://www.example.com/api/test',
xhrFields: {
withCredentials: true
}
});
Korzystanie z interfejsu API pobierania:
fetch('https://www.example.com/api/test', {
credentials: 'include'
});
Serwer musi zezwalać na poświadczenia. Aby zezwolić na poświadczenia między źródłami, wywołaj metodę AllowCredentials:
options.AddPolicy("MyMyAllowCredentialsPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.AllowCredentials();
});
Odpowiedź HTTP zawiera Access-Control-Allow-Credentials
nagłówek, który informuje przeglądarkę, że serwer zezwala na poświadczenia dla żądania między źródłami.
Jeśli przeglądarka wysyła poświadczenia, ale odpowiedź nie zawiera prawidłowego Access-Control-Allow-Credentials
nagłówka, przeglądarka nie uwidacznia odpowiedzi na aplikację, a żądanie między źródłami zakończy się niepowodzeniem.
Zezwolenie na poświadczenia między źródłami jest zagrożeniem bezpieczeństwa. Witryna internetowa w innej domenie może wysyłać poświadczenia zalogowanego użytkownika do aplikacji w imieniu użytkownika bez wiedzy użytkownika.
Specyfikacja MECHANIZMU CORS stwierdza również, że ustawienie wartości origins na "*"
(wszystkie źródła) jest nieprawidłowe, jeśli Access-Control-Allow-Credentials
nagłówek jest obecny.
Żądania wstępne
W przypadku niektórych żądań CORS przeglądarka wysyła dodatkowe żądanie OPTIONS przed wysłaniem rzeczywistego żądania. To żądanie jest nazywane żądaniem wstępnym. Przeglądarka może pominąć żądanie wstępne, jeśli spełnione są wszystkie następujące warunki:
- Metoda żądania to GET, HEAD lub POST.
- Aplikacja nie ustawia nagłówków żądań innych niż
Accept
, ,Accept-Language
,Content-Language
,Content-Type
lubLast-Event-ID
. - Nagłówek
Content-Type
, jeśli jest ustawiony, ma jedną z następujących wartości:application/x-www-form-urlencoded
multipart/form-data
text/plain
Reguła nagłówków żądań ustawiona dla żądania klienta ma zastosowanie do nagłówków ustawianych przez aplikację przez wywołanie setRequestHeader
XMLHttpRequest
obiektu. Specyfikacja MECHANIZMU CORS wywołuje te nagłówki żądań autora. Reguła nie ma zastosowania do nagłówków, które można ustawić w przeglądarce, takich jak User-Agent
, Host
lub Content-Length
.
Poniżej przedstawiono przykładową odpowiedź podobną do żądania wstępnego wykonanego z przycisku [Put test] w sekcji Test CORS tego dokumentu.
General:
Request URL: https://cors3.azurewebsites.net/api/values/5
Request Method: OPTIONS
Status Code: 204 No Content
Response Headers:
Access-Control-Allow-Methods: PUT,DELETE,GET
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f8...8;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Vary: Origin
Request Headers:
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Method: PUT
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0
Żądanie wstępne używa metody HTTP OPTIONS . Może zawierać następujące nagłówki:
- Access-Control-Request-Method: metoda HTTP, która będzie używana dla rzeczywistego żądania.
- Access-Control-Request-Headers: lista nagłówków żądań ustawianych przez aplikację w rzeczywistym żądaniu. Jak wspomniano wcześniej, nie zawiera to nagłówków ustawionych przez przeglądarkę, takich jak
User-Agent
. - Access-Control-Allow-Methods
Jeśli żądanie wstępne zostanie odrzucone, aplikacja zwróci 200 OK
odpowiedź, ale nie ustawi nagłówków CORS. W związku z tym przeglądarka nie podejmuje próby żądania między źródłami. Aby zapoznać się z przykładem odmowy żądania wstępnego, zobacz sekcję Test CORS tego dokumentu.
Za pomocą narzędzi F12 aplikacja konsolowa wyświetla błąd podobny do jednego z następujących, w zależności od przeglądarki:
- Firefox: Żądanie między źródłami zablokowane: Te same zasady pochodzenia nie zezwalają na odczytywanie zasobu zdalnego pod adresem
https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5
. (Przyczyna: żądanie CORS nie powiodło się). Dowiedz się więcej - Oparty na chromium: dostęp do pobierania z źródła "https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5https://cors3.azurewebsites.net" został zablokowany przez zasady CORS: Odpowiedź na żądanie wstępne nie przekazuje kontroli dostępu: Brak nagłówka "Access-Control-Allow-Origin" dla żądanego zasobu. Jeśli nieprzezroczysta odpowiedź spełnia Twoje potrzeby, ustaw tryb żądania na wartość "no-cors", aby pobrać zasób z wyłączonym mechanizmem CORS.
Aby zezwolić na określone nagłówki, wywołaj metodę WithHeaders:
options.AddPolicy("MyAllowHeadersPolicy",
policy =>
{
// requires using Microsoft.Net.Http.Headers;
policy.WithOrigins("http://example.com")
.WithHeaders(HeaderNames.ContentType, "x-custom-header");
});
Aby zezwolić na wszystkie nagłówki żądań autora, wywołaj metodę AllowAnyHeader:
options.AddPolicy("MyAllowAllHeadersPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.AllowAnyHeader();
});
Przeglądarki nie są spójne w sposobie ustawiania .Access-Control-Request-Headers
Jeśli:
- Nagłówki są ustawione na inne niż
"*"
- AllowAnyHeader jest wywoływany: uwzględnij co najmniej
Accept
,Content-Type
iOrigin
, oraz wszelkie nagłówki niestandardowe, które mają być obsługiwane.
Kod automatycznego żądania wstępnego
Po zastosowaniu zasad CORS:
- Globalnie przez wywołanie metody
app.UseCors
w plikuStartup.Configure
. - Za pomocą atrybutu
[EnableCors]
.
ASP.NET Core odpowiada na żądanie OPCJE wstępne.
Włączenie mechanizmu CORS dla poszczególnych punktów końcowych przy użyciu RequireCors
obecnie nie obsługuje automatycznych żądań wstępnych.
W sekcji Test CORS tego dokumentu pokazano to zachowanie.
[HttpOptions] atrybut dla żądań wstępnych
Gdy mechanizm CORS jest włączony z odpowiednimi zasadami, ASP.NET Core zwykle odpowiada na żądania wstępne CORS. W niektórych scenariuszach może to nie być możliwe. Na przykład użycie mechanizmu CORS z routingiem punktów końcowych.
Poniższy kod używa atrybutu [HttpOptions] do tworzenia punktów końcowych dla żądań OPTIONS:
[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
// OPTIONS: api/TodoItems2/5
[HttpOptions("{id}")]
public IActionResult PreflightRoute(int id)
{
return NoContent();
}
// OPTIONS: api/TodoItems2
[HttpOptions]
public IActionResult PreflightRoute()
{
return NoContent();
}
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id)
{
if (id < 1)
{
return BadRequest();
}
return ControllerContext.MyDisplayRouteInfo(id);
}
Aby uzyskać instrukcje dotyczące testowania poprzedniego kodu, zobacz Testowanie mechanizmu CORS przy użyciu routingu punktu końcowego i [HttpOptions ].
Ustawianie czasu wygaśnięcia przedlotu
Nagłówek Access-Control-Max-Age
określa, jak długo można buforować odpowiedź na żądanie wstępne. Aby ustawić ten nagłówek, wywołaj metodę SetPreflightMaxAge:
options.AddPolicy("MySetPreflightExpirationPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.SetPreflightMaxAge(TimeSpan.FromSeconds(2520));
});
Jak działa mechanizm CORS
W tej sekcji opisano, co dzieje się w żądaniu CORS na poziomie komunikatów HTTP.
- MECHANIZM CORS nie jest funkcją zabezpieczeń. CORS to standard W3C, który umożliwia serwerowi złagodzenie zasad tego samego źródła.
- Na przykład złośliwy aktor może użyć skryptów między witrynami (XSS) w witrynie i wykonać żądanie obejmujące wiele witryn do witryny obsługującej mechanizm CORS w celu kradzieży informacji.
- Interfejs API nie jest bezpieczniejszy, zezwalając na mechanizm CORS.
- Do klienta (przeglądarki) należy wymuszenie mechanizmu CORS. Serwer wykonuje żądanie i zwraca odpowiedź— klient zwraca błąd i blokuje odpowiedź. Na przykład dowolne z następujących narzędzi wyświetli odpowiedź serwera:
- Fiddler
- .NET HttpClient
- Przeglądarka internetowa, wprowadzając adres URL na pasku adresu.
- Do klienta (przeglądarki) należy wymuszenie mechanizmu CORS. Serwer wykonuje żądanie i zwraca odpowiedź— klient zwraca błąd i blokuje odpowiedź. Na przykład dowolne z następujących narzędzi wyświetli odpowiedź serwera:
- Jest to sposób na serwer, aby umożliwić przeglądarkom wykonywanie między źródłami żądania XHR lub Fetch API , które w przeciwnym razie byłoby zabronione.
- Przeglądarki bez mechanizmu CORS nie mogą wykonywać żądań między źródłami. Przed mechanizmem CORS kod JSONP został użyty do obejścia tego ograniczenia. JSONP nie używa XHR, używa tagu
<script>
do odbierania odpowiedzi. Skrypty mogą być ładowane między źródłami.
- Przeglądarki bez mechanizmu CORS nie mogą wykonywać żądań między źródłami. Przed mechanizmem CORS kod JSONP został użyty do obejścia tego ograniczenia. JSONP nie używa XHR, używa tagu
Specyfikacja MECHANIZMU CORS wprowadziła kilka nowych nagłówków HTTP, które umożliwiają żądania między źródłami. Jeśli przeglądarka obsługuje mechanizm CORS, automatycznie ustawia te nagłówki dla żądań między źródłami. Niestandardowy kod JavaScript nie jest wymagany do włączenia mechanizmu CORS.
Poniżej przedstawiono przykład żądania między źródłami z przycisku Test wartości do https://cors1.azurewebsites.net/api/values
. Nagłówek Origin
:
- Udostępnia domenę lokacji wysyłającej żądanie.
- Jest wymagany i musi być inny niż host.
Nagłówki ogólne
Request URL: https://cors1.azurewebsites.net/api/values
Request Method: GET
Status Code: 200 OK
Nagłówki odpowiedzi
Content-Encoding: gzip
Content-Type: text/plain; charset=utf-8
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors1.azurewebsites.net
Transfer-Encoding: chunked
Vary: Accept-Encoding
X-Powered-By: ASP.NET
Nagłówki żądań
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Connection: keep-alive
Host: cors1.azurewebsites.net
Origin: https://cors3.azurewebsites.net
Referer: https://cors3.azurewebsites.net/
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0 ...
W OPTIONS
żądaniach serwer ustawia nagłówek Nagłówki Access-Control-Allow-Origin: {allowed origin}
odpowiedzi w odpowiedzi. Na przykład wdrożone przykładowe żądanie przycisku OPTIONS
Usuń [EnableCors] zawiera następujące nagłówki:
Nagłówki ogólne
Request URL: https://cors3.azurewebsites.net/api/TodoItems2/MyDelete2/5
Request Method: OPTIONS
Status Code: 204 No Content
Nagłówki odpowiedzi
Access-Control-Allow-Headers: Content-Type,x-custom-header
Access-Control-Allow-Methods: PUT,DELETE,GET,OPTIONS
Access-Control-Allow-Origin: https://cors1.azurewebsites.net
Server: Microsoft-IIS/10.0
Set-Cookie: ARRAffinity=8f...;Path=/;HttpOnly;Domain=cors3.azurewebsites.net
Vary: Origin
X-Powered-By: ASP.NET
Nagłówki żądań
Accept: */*
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9
Access-Control-Request-Headers: content-type
Access-Control-Request-Method: DELETE
Connection: keep-alive
Host: cors3.azurewebsites.net
Origin: https://cors1.azurewebsites.net
Referer: https://cors1.azurewebsites.net/test?number=2
Sec-Fetch-Dest: empty
Sec-Fetch-Mode: cors
Sec-Fetch-Site: cross-site
User-Agent: Mozilla/5.0
W poprzednich nagłówkach Odpowiedzi serwer ustawia nagłówek Access-Control-Allow-Origin w odpowiedzi. Wartość https://cors1.azurewebsites.net
tego nagłówka odpowiada nagłówkowi Origin
z żądania.
Jeśli AllowAnyOrigin parametr jest wywoływany, zwracana jest wartość z symbolem Access-Control-Allow-Origin: *
wieloznacznymi. AllowAnyOrigin
zezwala na dowolne źródło.
Jeśli odpowiedź nie zawiera nagłówka Access-Control-Allow-Origin
, żądanie między źródłami zakończy się niepowodzeniem. W szczególności przeglądarka nie zezwala na żądanie. Nawet jeśli serwer zwróci pomyślną odpowiedź, przeglądarka nie udostępni odpowiedzi aplikacji klienckiej.
Wyświetlanie żądań OPTIONS
Domyślnie przeglądarki Chrome i Edge nie wyświetlają żądań OPTIONS na karcie sieci narzędzi F12. Aby wyświetlić żądania OPTIONS w następujących przeglądarkach:
chrome://flags/#out-of-blink-cors
lubedge://flags/#out-of-blink-cors
- wyłącz flagę.
- restart.
Przeglądarka Firefox domyślnie wyświetla żądania OPTIONS.
Mechanizm CORS w usługach IIS
Podczas wdrażania w usługach IIS mechanizm CORS musi działać przed uwierzytelnianiem systemu Windows, jeśli serwer nie jest skonfigurowany do zezwalania na dostęp anonimowy. Aby obsługiwać ten scenariusz, moduł CORS usług IIS musi zostać zainstalowany i skonfigurowany dla aplikacji.
Testowanie mechanizmu CORS
Przykładowy plik do pobrania zawiera kod do testowania mechanizmu CORS. Zobacz , jak pobrać. Przykład jest projektem interfejsu API z dodanymi stronami Razor :
public class StartupTest2
{
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(name: "MyPolicy",
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com",
"https://cors1.azurewebsites.net",
"https://cors3.azurewebsites.net",
"https://localhost:44398",
"https://localhost:5001")
.WithMethods("PUT", "DELETE", "GET");
});
});
services.AddControllers();
services.AddRazorPages();
}
public void Configure(IApplicationBuilder app)
{
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapRazorPages();
});
}
}
Ostrzeżenie
WithOrigins("https://localhost:<port>");
należy używać tylko do testowania przykładowej aplikacji podobnej do przykładowego kodu pobierania.
Poniżej przedstawiono ValuesController
punkty końcowe do testowania:
[EnableCors("MyPolicy")]
[Route("api/[controller]")]
[ApiController]
public class ValuesController : ControllerBase
{
// GET api/values
[HttpGet]
public IActionResult Get() =>
ControllerContext.MyDisplayRouteInfo();
// GET api/values/5
[HttpGet("{id}")]
public IActionResult Get(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// PUT api/values/5
[HttpPut("{id}")]
public IActionResult Put(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// GET: api/values/GetValues2
[DisableCors]
[HttpGet("{action}")]
public IActionResult GetValues2() =>
ControllerContext.MyDisplayRouteInfo();
}
MyDisplayRouteInfo jest dostarczany przez pakiet NuGet Rick.Docs.Samples.RouteInfo i wyświetla informacje o trasie.
Przetestuj poprzedni przykładowy kod przy użyciu jednego z następujących metod:
- Uruchom przykład przy
dotnet run
użyciu domyślnego adresu URL .https://localhost:5001
- Uruchom przykład z programu Visual Studio z portem ustawionym na 44398 jako adres URL
https://localhost:44398
.
Za pomocą przeglądarki z narzędziami F12:
Wybierz przycisk Wartości i przejrzyj nagłówki na karcie Sieć.
Wybierz przycisk TEST PUT. Zobacz Wyświetlanie żądań OPTIONS, aby uzyskać instrukcje dotyczące wyświetlania żądania OPTIONS. Test PUT tworzy dwa żądania, żądanie wstępne OPTIONS i żądanie PUT.
Wybierz przycisk,
GetValues2 [DisableCors]
aby wyzwolić nieudane żądanie CORS. Jak wspomniano w dokumencie, odpowiedź zwraca 200 powodzenia, ale żądanie CORS nie jest wykonywane. Wybierz kartę Konsola, aby wyświetlić błąd CORS. W zależności od przeglądarki zostanie wyświetlony błąd podobny do następującego:Dostęp do pobierania
'https://cors1.azurewebsites.net/api/values/GetValues2'
z źródła'https://cors3.azurewebsites.net'
został zablokowany przez zasady CORS: w żądanym zasobie nie ma nagłówka "Access-Control-Allow-Origin". Jeśli nieprzezroczysta odpowiedź spełnia Twoje potrzeby, ustaw tryb żądania na wartość "no-cors", aby pobrać zasób z wyłączonym mechanizmem CORS.
Punkty końcowe z obsługą mechanizmu CORS można przetestować za pomocą narzędzia, takiego jak curl lub Fiddler. W przypadku korzystania z narzędzia źródło żądania określonego przez Origin
nagłówek musi się różnić od hosta odbierającego żądanie. Jeśli żądanie nie jest źródłem krzyżowym na podstawie wartości nagłówka Origin
:
- Nie ma potrzeby przetwarzania żądania przez oprogramowanie pośredniczące CORS.
- Nagłówki CORS nie są zwracane w odpowiedzi.
Następujące polecenie używa curl
polecenia , aby wysłać żądanie OPTIONS z informacjami:
curl -X OPTIONS https://cors3.azurewebsites.net/api/TodoItems2/5 -i
Testowanie mechanizmu CORS przy użyciu routingu punktu końcowego i [HttpOptions]
Włączenie mechanizmu CORS dla poszczególnych punktów końcowych przy użyciu RequireCors
obecnie nie obsługuje automatycznych żądań wstępnych. Rozważmy następujący kod, który używa routingu punktu końcowego w celu włączenia mechanizmu CORS:
public class StartupEndPointBugTest
{
readonly string MyPolicy = "_myPolicy";
// .WithHeaders(HeaderNames.ContentType, "x-custom-header")
// forces browsers to require a preflight request with GET
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options =>
{
options.AddPolicy(name: MyPolicy,
policy =>
{
policy.WithOrigins("http://example.com",
"http://www.contoso.com",
"https://cors1.azurewebsites.net",
"https://cors3.azurewebsites.net",
"https://localhost:44398",
"https://localhost:5001")
.WithHeaders(HeaderNames.ContentType, "x-custom-header")
.WithMethods("PUT", "DELETE", "GET", "OPTIONS");
});
});
services.AddControllers();
services.AddRazorPages();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseCors();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers().RequireCors(MyPolicy);
endpoints.MapRazorPages();
});
}
}
Poniżej przedstawiono TodoItems1Controller
punkty końcowe do testowania:
[Route("api/[controller]")]
[ApiController]
public class TodoItems1Controller : ControllerBase
{
// PUT: api/TodoItems1/5
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id)
{
if (id < 1)
{
return Content($"ID = {id}");
}
return ControllerContext.MyDisplayRouteInfo(id);
}
// Delete: api/TodoItems1/5
[HttpDelete("{id}")]
public IActionResult MyDelete(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
// GET: api/TodoItems1
[HttpGet]
public IActionResult GetTodoItems() =>
ControllerContext.MyDisplayRouteInfo();
[EnableCors]
[HttpGet("{action}")]
public IActionResult GetTodoItems2() =>
ControllerContext.MyDisplayRouteInfo();
// Delete: api/TodoItems1/MyDelete2/5
[EnableCors]
[HttpDelete("{action}/{id}")]
public IActionResult MyDelete2(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
}
Przetestuj powyższy kod ze strony testowej (https://cors1.azurewebsites.net/test?number=1
) wdrożonego przykładu.
Przyciski Usuń [EnableCors] i GET [EnableCors] kończą się powodzeniem, ponieważ punkty końcowe mają [EnableCors]
żądania wstępne i odpowiadają na nie. Inne punkty końcowe kończą się niepowodzeniem. Przycisk GET kończy się niepowodzeniem, ponieważ skrypt JavaScript wysyła:
headers: {
"Content-Type": "x-custom-header"
},
Poniższe informacje TodoItems2Controller
zawierają podobne punkty końcowe, ale zawierają jawny kod, który odpowiada na żądania OPTIONS:
[Route("api/[controller]")]
[ApiController]
public class TodoItems2Controller : ControllerBase
{
// OPTIONS: api/TodoItems2/5
[HttpOptions("{id}")]
public IActionResult PreflightRoute(int id)
{
return NoContent();
}
// OPTIONS: api/TodoItems2
[HttpOptions]
public IActionResult PreflightRoute()
{
return NoContent();
}
[HttpPut("{id}")]
public IActionResult PutTodoItem(int id)
{
if (id < 1)
{
return BadRequest();
}
return ControllerContext.MyDisplayRouteInfo(id);
}
// [EnableCors] // Not needed as OPTIONS path provided
[HttpDelete("{id}")]
public IActionResult MyDelete(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
[EnableCors] // Rquired for this path
[HttpGet]
public IActionResult GetTodoItems() =>
ControllerContext.MyDisplayRouteInfo();
[HttpGet("{action}")]
public IActionResult GetTodoItems2() =>
ControllerContext.MyDisplayRouteInfo();
[EnableCors] // Rquired for this path
[HttpDelete("{action}/{id}")]
public IActionResult MyDelete2(int id) =>
ControllerContext.MyDisplayRouteInfo(id);
}
Powyższy kod można przetestować, wdrażając przykład w celu Azure.In listy rozwijanej Kontroler, wybierz pozycję Wstępne, a następnie ustaw kontroler. Wszystkie wywołania CORS do punktów końcowych kończą się powodzeniem TodoItems2Controller
.