События
31 мар., 23 - 2 апр., 23
Конечное событие Power BI, Fabric, SQL и ai community. 31 марта – 2 апреля. Используйте код MSCUST для скидки на $150. Цены выросли на 11 февраля.
Зарегистрироваться сегодняЭтот браузер больше не поддерживается.
Выполните обновление до Microsoft Edge, чтобы воспользоваться новейшими функциями, обновлениями для системы безопасности и технической поддержкой.
Примечание
Это не последняя версия этой статьи. В текущем выпуске см . версию .NET 9 этой статьи.
Предупреждение
Эта версия ASP.NET Core больше не поддерживается. Дополнительные сведения см. в политике поддержки .NET и .NET Core. В текущем выпуске см . версию .NET 9 этой статьи.
Важно!
Эта информация относится к предварительному выпуску продукта, который может быть существенно изменен до его коммерческого выпуска. Майкрософт не предоставляет никаких гарантий, явных или подразумеваемых, относительно приведенных здесь сведений.
В текущем выпуске см . версию .NET 9 этой статьи.
Авторы: Рик Андерсон (Rick Anderson) и Кирк Ларкин (Kirk Larkin)
В этой статье показано, как Cross-O rigin Resource Sharing (CORS) включен в приложении ASP.NET Core.
Система безопасности браузера предотвращает запросы веб-страницы к другому домену, отличному от того, который обслуживает веб-страницу. Это ограничение называется политика одного источника. Эта политика предотвращает чтение вредоносным сайтом конфиденциальных данных с другого сайта. Иногда вы должны разрешить другим сайтам выполнять запросы к приложению независимо от источника. Дополнительные сведения см. в статье Mozilla CORS.
Общий доступ к ресурсам между источниками (CORS):
Просмотреть или скачать образец кода (описание загрузки)
Два URL-адреса имеют одинаковый источник, если они имеют одинаковые схемы, узлы и порты (RFC 6454).
Эти два URL-адреса имеют одинаковый источник:
https://example.com/foo.html
https://example.com/bar.html
Эти URL-адреса имеют разные источники, отличные от предыдущих двух URL-адресов:
https://example.net
: другой доменhttps://contoso.example.com/foo.html
: другой поддоменhttp://example.com/foo.html
: другая схемаhttps://example.com:9000/foo.html
: другой портСуществует три способа включения CORS:
Использование атрибута [EnableCors] с именованной политикой обеспечивает лучший контроль в ограничении конечных точек, поддерживающих CORS.
Предупреждение
UseCors должен вызываться в правильном порядке. Дополнительные сведения см. в порядке по промежуточного слоя. Например, UseCors
необходимо вызвать перед UseResponseCaching использованием UseResponseCaching
.
Каждый подход подробно описан в следующих разделах.
ПО промежуточного слоя CORS обрабатывает запросы между источниками. Следующий код применяет политику CORS ко всем конечным точкам приложения с указанными источниками:
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();
Предыдущий код:
_myAllowSpecificOrigins
имени политики значение . Имя политики является произвольным._myAllowSpecificOrigins
политику CORS. UseCors
добавляет ПО промежуточного слоя CORS. UseCors
Вызов должен быть помещен после UseRouting
, но до UseAuthorization
. Дополнительные сведения см. в порядке по промежуточного слоя.WithOrigins
, описаны далее в этой статье._myAllowSpecificOrigins
Включает политику CORS для всех конечных точек контроллера. См. маршрутизацию конечных точек, чтобы применить политику CORS к определенным конечным точкам.При маршрутизации конечных точек ПО промежуточного слоя CORS необходимо настроить для выполнения между вызовами UseRouting
и UseEndpoints
.
Вызов AddCors метода добавляет службы CORS в контейнер службы приложения:
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();
Дополнительные сведения см. в разделе "Параметры политики CORS" в этом документе.
Методы CorsPolicyBuilder можно связать, как показано в следующем коде:
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();
Примечание. Указанный URL-адрес не должен содержать косую черту (/
). Если URL-адрес завершается /
, сравнение возвращается false
и заголовок не возвращается.
Как правило, UseStaticFiles
вызывается раньше UseCors
. Приложения, использующие JavaScript для получения статических файлов, должны вызываться перед UseStaticFiles
вызовомUseCors
.
Следующий выделенный код включает политику 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();
Приведенный выше код применяет политику CORS по умолчанию ко всем конечным точкам контроллера.
При маршрутизации конечных точек CORS можно включить на основе каждой конечной точки с помощью RequireCors набора методов расширения:
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();
В предыдущем коде:
app.UseCors
включает ПО промежуточного слоя CORS. Так как политика по умолчанию не настроена, app.UseCors()
только не включает CORS./echo
точки и конечные точки контроллера разрешают запросы между источниками с помощью указанной политики./echo2
точки и Razor страницы не разрешают запросы между источниками, так как политика по умолчанию не указана.Атрибут [DisableCors] не отключает CORS, включенную маршрутизацией конечных точек.RequireCors
Ознакомьтесь с атрибутом Test CORS с атрибутом [EnableCors] и методом RequireCors для инструкций по тестированию кода, аналогичного приведенному выше.
Включение CORS с атрибутом [EnableCors] и применение именованной политики только к тем конечным точкам, которым требуется CORS, обеспечивает лучший контроль.
Атрибут [EnableCors] предоставляет альтернативу применению CORS глобально. Атрибут [EnableCors]
включает CORS для выбранных конечных точек, а не для всех конечных точек:
[EnableCors]
указывает политику по умолчанию.[EnableCors("{Policy String}")]
указывает именованную политику.Атрибут [EnableCors]
можно применить к:
PageModel
Различные политики можно применять к контроллерам, моделям страниц или методам действий с атрибутом [EnableCors]
. [EnableCors]
Если атрибут применяется к контроллеру, модели страницы или методу действия, а CORS включен в ПО промежуточного слоя, применяются обе политики. Рекомендуется объединять политики. Используйте[EnableCors]
атрибут или ПО промежуточного слоя, а не в одном приложении.
Следующий код применяет другую политику к каждому методу:
[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(),
};
}
}
Следующий код создает две политики 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();
Для лучшего контроля ограничения запросов CORS:
[EnableCors("MyPolicy")]
с именованной политикой.Код в следующем разделе соответствует предыдущему списку.
Атрибут [DisableCors] не отключает CORS, включенную маршрутизацией конечных точек.
Следующий код определяет политику "MyPolicy"
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();
Следующий код отключает CORS для GetValues2
действия:
[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();
}
Предыдущий код:
"MyPolicy"
политики CORS для контроллера.GetValues2
метода.Сведения о тестировании предыдущего кода см. в разделе Test CORS .
В этом разделе описаны различные параметры, которые можно задать в политике CORS:
AddPolicy вызывается в Program.cs
. Для некоторых вариантов может быть полезно сначала ознакомиться с разделом о работе CORS.
AllowAnyOrigin: разрешает запросы CORS из всех источников с любой схемой (http
или https
). AllowAnyOrigin
небезопасно, так как любой веб-сайт может выполнять запросы между источниками приложения.
Примечание
Указание AllowAnyOrigin
и AllowCredentials
является небезопасной конфигурацией и может привести к подделке межсайтовых запросов. Служба CORS возвращает недопустимый ответ CORS, если приложение настроено с использованием обоих методов.
AllowAnyOrigin
влияет на предварительные Access-Control-Allow-Origin
запросы и заголовок. Дополнительные сведения см. в разделе "Предварительные запросы ".
SetIsOriginAllowedToAllowWildcardSubdomains: задает IsOriginAllowed свойство политики, которая позволяет источникам сопоставлять настроенный домен подстановочных знаков при оценке допустимости источника.
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();
Access-Control-Allow-Methods
запросы и заголовок. Дополнительные сведения см. в разделе "Предварительные запросы ".Чтобы разрешить отправку определенных заголовков в запросе CORS, называется заголовками запросов автора, вызовом WithHeaders и указанием разрешенных заголовков:
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();
Чтобы разрешить все заголовки запросов автора, вызовите 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
влияет на предварительные запросы и заголовок Access-Control-Request-Headers . Дополнительные сведения см. в разделе "Предварительные запросы ".
Политика ПО промежуточного слоя CORS соответствует определенным заголовкам, указанным WithHeaders
только в том случае, если заголовки, отправленные точно Access-Control-Request-Headers
соответствуют заголовкам, указанным в .WithHeaders
Например, рассмотрим приложение, настроенное следующим образом:
app.UseCors(policy => policy.WithHeaders(HeaderNames.CacheControl));
ПО промежуточного слоя CORS отклоняет предварительный запрос со следующим заголовком запроса, так как Content-Language
(HeaderNames.ContentLanguage) не указан вWithHeaders
:
Access-Control-Request-Headers: Cache-Control, Content-Language
Приложение возвращает ответ 200 OK , но не отправляет заголовки CORS обратно. Поэтому браузер не пытается выполнить запрос между источниками.
По умолчанию браузер не предоставляет все заголовки ответа приложению. Дополнительные сведения см. в разделе "Общий доступ к ресурсам между источниками W3C" (терминология): простой заголовок ответа.
Заголовки ответов, доступные по умолчанию:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
Спецификация CORS вызывает эти заголовки простых заголовков ответа. Чтобы сделать другие заголовки доступными для приложения, вызовите 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();
Учетные данные требуют специальной обработки в запросе CORS. По умолчанию браузер не отправляет учетные данные с запросом между источниками. Учетные данные включают файлы cookie и схемы проверки подлинности HTTP. Чтобы отправить учетные данные с запросом между источниками, клиент должен задать значение XMLHttpRequest.withCredentials
true
.
Использование XMLHttpRequest
напрямую:
var xhr = new XMLHttpRequest();
xhr.open('get', 'https://www.example.com/api/test');
xhr.withCredentials = true;
Использование jQuery:
$.ajax({
type: 'get',
url: 'https://www.example.com/api/test',
xhrFields: {
withCredentials: true
}
});
Использование API получения:
fetch('https://www.example.com/api/test', {
credentials: 'include'
});
Сервер должен разрешить учетные данные. Чтобы разрешить учетные данные между источниками, вызовите 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();
Http-ответ содержит заголовок, который сообщает браузеру Access-Control-Allow-Credentials
, что сервер разрешает учетные данные для запроса между источниками.
Если браузер отправляет учетные данные, но ответ не содержит допустимый Access-Control-Allow-Credentials
заголовок, браузер не предоставляет ответ приложению, а запрос между источниками завершается ошибкой.
Разрешение учетных данных между источниками — это риск безопасности. Веб-сайт в другом домене может отправлять учетные данные пользователя, выполнившего вход, в приложение от имени пользователя без знаний пользователя.
Спецификация CORS также указывает, что установка источников "*"
(всех источников) недопустима, если заголовок Access-Control-Allow-Credentials
присутствует.
Для некоторых запросов CORS браузер отправляет дополнительный запрос OPTIONS перед выполнением фактического запроса. Этот запрос называется предварительным запросом. Браузер может пропустить предварительный запрос, если выполняются все следующие условия:
Accept
, Accept-Language
, , Content-Language
Content-Type
или Last-Event-ID
.Content-Type
, если задано, имеет одно из следующих значений: application/x-www-form-urlencoded
multipart/form-data
text/plain
Правило заголовков запросов, заданных для клиентского запроса, применяется к заголовкам, заданным приложением путем вызова setRequestHeader
XMLHttpRequest
объекта. Спецификация CORS вызывает эти заголовки для создания запросов. Правило не применяется к заголовкам, которые браузер может задать, например User-Agent
, Host
или Content-Length
.
Примечание
В этой статье содержатся URL-адреса, созданные путем развертывания примера кода на двух веб-сайтах https://cors3.azurewebsites.net
Azure и https://cors.azurewebsites.net
.
Ниже приведен пример ответа, аналогичного запросу предварительной проверки, сделанному на кнопке [Put test] в разделе Test CORS этого документа.
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
Предварительный запрос использует метод HTTP OPTIONS . Он может включать следующие заголовки:
User-Agent
.Если запрос на предварительную 200 OK
проверку запрещен, приложение возвращает ответ, но не задает заголовки CORS. Поэтому браузер не пытается выполнить запрос между источниками. Пример отклоненного предварительного запроса см. в разделе test CORS этого документа.
С помощью средств F12 консольное приложение отображает ошибку, аналогичную одной из следующих, в зависимости от браузера:
https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5
. (Причина: запрос CORS не выполнен). ПодробнееЧтобы разрешить определенные заголовки, вызовите 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();
Чтобы разрешить все заголовки запросов автора, вызовите 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();
Браузеры не согласованы в том, как они заданы Access-Control-Request-Headers
. Если одно из следующих вариантов:
"*"
Accept
, Content-Type
и Origin
, а также все пользовательские заголовки, которые требуется поддерживать.При применении политики CORS:
app.UseCors
Program.cs
.[EnableCors]
.ASP.NET Core отвечает на запрос параметров предварительной проверки.
В разделе Test CORS этого документа показано это поведение.
Если CORS включена с соответствующей политикой, ASP.NET Core обычно реагирует на запросы предварительной проверки CORS автоматически.
Следующий код использует атрибут [HttpOptions] для создания конечных точек для запросов 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);
}
Сведения о тестировании предыдущего кода см. в разделе Test CORS с атрибутом [EnableCors] и методОм RequireCors.
Заголовок Access-Control-Max-Age
указывает, сколько времени можно кэшировать ответ на предварительный запрос. Чтобы задать этот заголовок, вызовите 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();
В этом разделе описывается, что происходит в запросе CORS на уровне HTTP-сообщений.
<script>
тег для получения ответа. Скрипты могут загружаться между источниками.Спецификация CORS представила несколько новых заголовков HTTP, которые позволяют выполнять запросы между источниками. Если браузер поддерживает CORS, он автоматически задает эти заголовки для запросов между источниками. Пользовательский код JavaScript не требуется для включения CORS.
Ниже приведен пример запроса между источниками из кнопки "Тест значений " в https://cors1.azurewebsites.net/api/values
. Заголовок Origin
:
Общие заголовки
Request URL: https://cors1.azurewebsites.net/api/values
Request Method: GET
Status Code: 200 OK
Заголовки ответа
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
Заголовки запроса
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 ...
В OPTIONS
запросах сервер задает заголовок заголовков Access-Control-Allow-Origin: {allowed origin}
ответа в ответе. Например, в примере кода Delete [EnableCors]
запрос кнопки OPTIONS
содержит следующие заголовки:
Общие заголовки
Request URL: https://cors3.azurewebsites.net/api/TodoItems2/MyDelete2/5
Request Method: OPTIONS
Status Code: 204 No Content
Заголовки ответа
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
Заголовки запроса
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
В предыдущих заголовках ответа сервер задает заголовок Access-Control-Allow-Origin в ответе. Значение https://cors1.azurewebsites.net
этого заголовка соответствует заголовку Origin
из запроса.
Если AllowAnyOrigin вызывается, Access-Control-Allow-Origin: *
возвращается подстановочное значение. AllowAnyOrigin
разрешает любой источник.
Если ответ не включает Access-Control-Allow-Origin
заголовок, запрос между источниками завершается ошибкой. В частности, браузер запрещает запрос. Даже если сервер возвращает успешный ответ, браузер не делает ответ доступным для клиентского приложения.
Запросы к конечной точке с использованием HTTP, перенаправленных на HTTPS, сбоем UseHttpsRedirection ERR_INVALID_REDIRECT on the CORS preflight request
.
Проекты API могут отклонять HTTP-запросы, а не использовать UseHttpsRedirection
для перенаправления запросов на HTTPS.
При развертывании в IIS CORS необходимо запустить перед проверкой подлинности Windows, если сервер не настроен для предоставления анонимного доступа. Для поддержки этого сценария необходимо установить и настроить модуль IIS CORS для приложения.
Пример скачивания содержит код для тестирования CORS. См. раздел Практическое руководство. Скачивание файла. Примером является проект API с 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();
Предупреждение
WithOrigins("https://localhost:<port>");
следует использовать только для тестирования примера приложения, аналогичного примеру кода скачивания.
ValuesController
Ниже приведены конечные точки для тестирования:
[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 предоставляется пакетом NuGet Rick.Docs.Samples.RouteInfo и отображает информацию о маршруте.
Протестируйте предыдущий пример кода с помощью одного из следующих подходов:
dotnet run
использованием URL-адреса https://localhost:5001
по умолчанию.https://localhost:44398
.Использование браузера с инструментами F12:
Нажмите кнопку "Значения" и просмотрите заголовки на вкладке "Сеть".
Нажмите кнопку "Тест PUT ". Сведения о отображении запроса OPTIONS см. в разделе "Запросы ПАРАМЕТРОВ ". Тест PUT создает два запроса, предварительный запрос OPTIONS и запрос PUT.
Нажмите кнопку GetValues2 [DisableCors]
, чтобы активировать неудачный запрос CORS. Как упоминалось в документе, ответ возвращает 200 успешно, но запрос CORS не выполняется. Перейдите на вкладку "Консоль", чтобы увидеть ошибку CORS. В зависимости от браузера отображается ошибка, аналогичная следующему:
Доступ к получению 'https://cors1.azurewebsites.net/api/values/GetValues2'
из источника 'https://cors3.azurewebsites.net'
заблокирован политикой CORS: в запрошенном ресурсе отсутствует заголовок Access-Control-Allow-Origin. Если этот непрозрачный ответ вам подходит, задайте для режима запроса значение "no-cors", чтобы извлечь ресурс с отключенным параметром CORS.
Конечные точки с поддержкой CORS можно протестировать с помощью средства, например curl или Fiddler. При использовании средства источник запроса, указанного Origin
заголовком, должен отличаться от узла, получающего запрос. Если запрос не является кросс-источником на основе значения заголовка Origin
:
Следующая команда используется curl
для выдачи запроса OPTIONS с информацией:
curl -X OPTIONS https://cors3.azurewebsites.net/api/TodoItems2/5 -i
Рассмотрим следующий код, который использует маршрутизацию конечных точек для включения CORS на основе каждой конечной точки с помощью 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();
Обратите внимание, что только /echo
конечная точка используется RequireCors
для разрешения запросов между источниками с помощью указанной политики. Приведенные ниже контроллеры позволяют CORS использовать атрибут [EnableCors].
TodoItems1Controller
Ниже приведены конечные точки для тестирования:
[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);
}
Кнопки Delete [EnableCors] и GET [EnableCors] успешно выполнены, так как конечные точки имеют [EnableCors]
и отвечают на предварительные запросы. Сбой других конечных точек. Кнопка GET завершается ошибкой, так как JavaScript отправляет:
headers: {
"Content-Type": "x-custom-header"
},
TodoItems2Controller
Ниже приведены аналогичные конечные точки, но содержит явный код для реагирования на запросы 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);
}
Приведенный выше код можно проверить, развернув пример в Azure. В раскрывающемся списке контроллера выберите "Предварительная проверка " и " Задать контроллер". Все вызовы CORS к TodoItems2Controller
конечным точкам успешно выполнены.
Авторы: Рик Андерсон (Rick Anderson) и Кирк Ларкин (Kirk Larkin)
В этой статье показано, как включить CORS в приложении ASP.NET Core.
Система безопасности браузера предотвращает запросы веб-страницы к другому домену, отличному от того, который обслуживает веб-страницу. Это ограничение называется политика одного источника. Эта политика предотвращает чтение вредоносным сайтом конфиденциальных данных с другого сайта. Иногда вы должны разрешить другим сайтам выполнять запросы к приложению независимо от источника. Дополнительные сведения см. в статье Mozilla CORS.
Общий доступ к ресурсам между источниками (CORS):
Просмотреть или скачать образец кода (описание загрузки)
Два URL-адреса имеют одинаковый источник, если они имеют одинаковые схемы, узлы и порты (RFC 6454).
Эти два URL-адреса имеют одинаковый источник:
https://example.com/foo.html
https://example.com/bar.html
Эти URL-адреса имеют разные источники, отличные от предыдущих двух URL-адресов:
https://example.net
: другой доменhttps://www.example.com/foo.html
: другой поддоменhttp://example.com/foo.html
: другая схемаhttps://example.com:9000/foo.html
: другой портСуществует три способа включения CORS:
Использование атрибута [EnableCors] с именованной политикой обеспечивает лучший контроль в ограничении конечных точек, поддерживающих CORS.
Предупреждение
UseCors должен вызываться в правильном порядке. Дополнительные сведения см. в порядке по промежуточного слоя. Например, UseCors
необходимо вызвать перед UseResponseCaching использованием UseResponseCaching
.
Каждый подход подробно описан в следующих разделах.
ПО промежуточного слоя CORS обрабатывает запросы между источниками. Следующий код применяет политику CORS ко всем конечным точкам приложения с указанными источниками:
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();
Предыдущий код:
_myAllowSpecificOrigins
имени политики значение . Имя политики является произвольным._myAllowSpecificOrigins
политику CORS. UseCors
добавляет ПО промежуточного слоя CORS. UseCors
Вызов должен быть помещен после UseRouting
, но до UseAuthorization
. Дополнительные сведения см. в порядке по промежуточного слоя.WithOrigins
, описаны далее в этой статье._myAllowSpecificOrigins
Включает политику CORS для всех конечных точек контроллера. См. маршрутизацию конечных точек, чтобы применить политику CORS к определенным конечным точкам.При маршрутизации конечных точек ПО промежуточного слоя CORS необходимо настроить для выполнения между вызовами UseRouting
и UseEndpoints
.
Вызов AddCors метода добавляет службы CORS в контейнер службы приложения:
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();
Дополнительные сведения см. в разделе "Параметры политики CORS" в этом документе.
Методы CorsPolicyBuilder можно связать, как показано в следующем коде:
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();
Примечание. Указанный URL-адрес не должен содержать косую черту (/
). Если URL-адрес завершается /
, сравнение возвращается false
и заголовок не возвращается.
Предупреждение
UseCors
должно быть помещено после UseRouting
и до UseAuthorization
. Это позволяет убедиться, что заголовки CORS включены в ответ как для авторизованных, так и для несанкционированных вызовов.
Как правило, UseStaticFiles
вызывается раньше UseCors
. Приложения, использующие JavaScript для получения статических файлов, должны вызываться перед UseStaticFiles
вызовомUseCors
.
Следующий выделенный код включает политику 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();
Приведенный выше код применяет политику CORS по умолчанию ко всем конечным точкам контроллера.
При маршрутизации конечных точек CORS можно включить на основе каждой конечной точки с помощью RequireCors набора методов расширения:
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();
В предыдущем коде:
app.UseCors
включает ПО промежуточного слоя CORS. Так как политика по умолчанию не настроена, app.UseCors()
только не включает CORS./echo
точки и конечные точки контроллера разрешают запросы между источниками с помощью указанной политики./echo2
точки и Razor страницы не разрешают запросы между источниками, так как политика по умолчанию не указана.Атрибут [DisableCors] не отключает CORS, включенную маршрутизацией конечных точек.RequireCors
В ASP.NET Core 7.0 [EnableCors]
атрибут должен передать параметр или предупреждение ASP0023 создается из неоднозначного соответствия маршрута. ASP.NET Core 8.0 и более поздних версий ASP0023
не создает предупреждение.
[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);
}
Ознакомьтесь с атрибутом Test CORS с атрибутом [EnableCors] и методом RequireCors для инструкций по тестированию кода, аналогичного приведенному выше.
Включение CORS с атрибутом [EnableCors] и применение именованной политики только к тем конечным точкам, которым требуется CORS, обеспечивает лучший контроль.
Атрибут [EnableCors] предоставляет альтернативу применению CORS глобально. Атрибут [EnableCors]
включает CORS для выбранных конечных точек, а не для всех конечных точек:
[EnableCors]
указывает политику по умолчанию.[EnableCors("{Policy String}")]
указывает именованную политику.Атрибут [EnableCors]
можно применить к:
PageModel
Различные политики можно применять к контроллерам, моделям страниц или методам действий с атрибутом [EnableCors]
. [EnableCors]
Если атрибут применяется к контроллеру, модели страницы или методу действия, а CORS включен в ПО промежуточного слоя, применяются обе политики. Рекомендуется объединять политики. Используйте[EnableCors]
атрибут или ПО промежуточного слоя, а не в одном приложении.
Следующий код применяет другую политику к каждому методу:
[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(),
};
}
}
Следующий код создает две политики 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();
Для лучшего контроля ограничения запросов CORS:
[EnableCors("MyPolicy")]
с именованной политикой.Код в следующем разделе соответствует предыдущему списку.
Атрибут [DisableCors] не отключает CORS, включенную маршрутизацией конечных точек.
Следующий код определяет политику "MyPolicy"
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();
Следующий код отключает CORS для GetValues2
действия:
[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();
}
Предыдущий код:
"MyPolicy"
политики CORS для контроллера.GetValues2
метода.Сведения о тестировании предыдущего кода см. в разделе Test CORS .
В этом разделе описаны различные параметры, которые можно задать в политике CORS:
AddPolicy вызывается в Program.cs
. Для некоторых вариантов может быть полезно сначала ознакомиться с разделом о работе CORS.
AllowAnyOrigin: разрешает запросы CORS из всех источников с любой схемой (http
или https
). AllowAnyOrigin
небезопасно, так как любой веб-сайт может выполнять запросы между источниками приложения.
Примечание
Указание AllowAnyOrigin
и AllowCredentials
является небезопасной конфигурацией и может привести к подделке межсайтовых запросов. Служба CORS возвращает недопустимый ответ CORS, если приложение настроено с использованием обоих методов.
AllowAnyOrigin
влияет на предварительные Access-Control-Allow-Origin
запросы и заголовок. Дополнительные сведения см. в разделе "Предварительные запросы ".
SetIsOriginAllowedToAllowWildcardSubdomains: задает IsOriginAllowed свойство политики, которая позволяет источникам сопоставлять настроенный домен подстановочных знаков при оценке допустимости источника.
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();
Access-Control-Allow-Methods
запросы и заголовок. Дополнительные сведения см. в разделе "Предварительные запросы ".Чтобы разрешить отправку определенных заголовков в запросе CORS, называется заголовками запросов автора, вызовом WithHeaders и указанием разрешенных заголовков:
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();
Чтобы разрешить все заголовки запросов автора, вызовите 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
влияет на предварительные запросы и заголовок Access-Control-Request-Headers . Дополнительные сведения см. в разделе "Предварительные запросы ".
Политика ПО промежуточного слоя CORS соответствует определенным заголовкам, указанным WithHeaders
только в том случае, если заголовки, отправленные точно Access-Control-Request-Headers
соответствуют заголовкам, указанным в .WithHeaders
Например, рассмотрим приложение, настроенное следующим образом:
app.UseCors(policy => policy.WithHeaders(HeaderNames.CacheControl));
ПО промежуточного слоя CORS отклоняет предварительный запрос со следующим заголовком запроса, так как Content-Language
(HeaderNames.ContentLanguage) не указан вWithHeaders
:
Access-Control-Request-Headers: Cache-Control, Content-Language
Приложение возвращает ответ 200 OK , но не отправляет заголовки CORS обратно. Поэтому браузер не пытается выполнить запрос между источниками.
По умолчанию браузер не предоставляет все заголовки ответа приложению. Дополнительные сведения см. в разделе "Общий доступ к ресурсам между источниками W3C" (терминология): простой заголовок ответа.
Заголовки ответов, доступные по умолчанию:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
Спецификация CORS вызывает эти заголовки простых заголовков ответа. Чтобы сделать другие заголовки доступными для приложения, вызовите 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();
Учетные данные требуют специальной обработки в запросе CORS. По умолчанию браузер не отправляет учетные данные с запросом между источниками. Учетные данные включают файлы cookie и схемы проверки подлинности HTTP. Чтобы отправить учетные данные с запросом между источниками, клиент должен задать значение XMLHttpRequest.withCredentials
true
.
Использование XMLHttpRequest
напрямую:
var xhr = new XMLHttpRequest();
xhr.open('get', 'https://www.example.com/api/test');
xhr.withCredentials = true;
Использование jQuery:
$.ajax({
type: 'get',
url: 'https://www.example.com/api/test',
xhrFields: {
withCredentials: true
}
});
Использование API получения:
fetch('https://www.example.com/api/test', {
credentials: 'include'
});
Сервер должен разрешить учетные данные. Чтобы разрешить учетные данные между источниками, вызовите 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();
Http-ответ содержит заголовок, который сообщает браузеру Access-Control-Allow-Credentials
, что сервер разрешает учетные данные для запроса между источниками.
Если браузер отправляет учетные данные, но ответ не содержит допустимый Access-Control-Allow-Credentials
заголовок, браузер не предоставляет ответ приложению, а запрос между источниками завершается ошибкой.
Разрешение учетных данных между источниками — это риск безопасности. Веб-сайт в другом домене может отправлять учетные данные пользователя, выполнившего вход, в приложение от имени пользователя без знаний пользователя.
Спецификация CORS также указывает, что установка источников "*"
(всех источников) недопустима, если заголовок Access-Control-Allow-Credentials
присутствует.
Для некоторых запросов CORS браузер отправляет дополнительный запрос OPTIONS перед выполнением фактического запроса. Этот запрос называется предварительным запросом. Браузер может пропустить предварительный запрос, если выполняются все следующие условия:
Accept
, Accept-Language
, , Content-Language
Content-Type
или Last-Event-ID
.Content-Type
, если задано, имеет одно из следующих значений: application/x-www-form-urlencoded
multipart/form-data
text/plain
Правило заголовков запросов, заданных для клиентского запроса, применяется к заголовкам, заданным приложением путем вызова setRequestHeader
XMLHttpRequest
объекта. Спецификация CORS вызывает эти заголовки для создания запросов. Правило не применяется к заголовкам, которые браузер может задать, например User-Agent
, Host
или Content-Length
.
Ниже приведен пример ответа, аналогичного запросу предварительной проверки, сделанному на кнопке [Put test] в разделе Test CORS этого документа.
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
Предварительный запрос использует метод HTTP OPTIONS . Он может включать следующие заголовки:
User-Agent
.Если запрос на предварительную 200 OK
проверку запрещен, приложение возвращает ответ, но не задает заголовки CORS. Поэтому браузер не пытается выполнить запрос между источниками. Пример отклоненного предварительного запроса см. в разделе test CORS этого документа.
С помощью средств F12 консольное приложение отображает ошибку, аналогичную одной из следующих, в зависимости от браузера:
https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5
. (Причина: запрос CORS не выполнен). ПодробнееЧтобы разрешить определенные заголовки, вызовите 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();
Чтобы разрешить все заголовки запросов автора, вызовите 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();
Браузеры не согласованы в том, как они заданы Access-Control-Request-Headers
. Если одно из следующих вариантов:
"*"
Accept
, Content-Type
и Origin
, а также все пользовательские заголовки, которые требуется поддерживать.При применении политики CORS:
app.UseCors
Program.cs
.[EnableCors]
.ASP.NET Core отвечает на запрос параметров предварительной проверки.
В разделе Test CORS этого документа показано это поведение.
Если CORS включена с соответствующей политикой, ASP.NET Core обычно реагирует на запросы предварительной проверки CORS автоматически.
Следующий код использует атрибут [HttpOptions] для создания конечных точек для запросов 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);
}
Сведения о тестировании предыдущего кода см. в разделе Test CORS с атрибутом [EnableCors] и методОм RequireCors.
Заголовок Access-Control-Max-Age
указывает, сколько времени можно кэшировать ответ на предварительный запрос. Чтобы задать этот заголовок, вызовите 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();
В этом разделе описывается, что происходит в запросе CORS на уровне HTTP-сообщений.
<script>
тег для получения ответа. Скрипты могут загружаться между источниками.Спецификация CORS представила несколько новых заголовков HTTP, которые позволяют выполнять запросы между источниками. Если браузер поддерживает CORS, он автоматически задает эти заголовки для запросов между источниками. Пользовательский код JavaScript не требуется для включения CORS.
Нажмите кнопку PUT теста в развернутом примере.
Заголовок Origin
:
Общие заголовки
Request URL: https://cors1.azurewebsites.net/api/values
Request Method: GET
Status Code: 200 OK
Заголовки ответа
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
Заголовки запроса
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 ...
В OPTIONS
запросах сервер задает заголовок заголовков Access-Control-Allow-Origin: {allowed origin}
ответа в ответе. Например, в примере кода Delete [EnableCors]
запрос кнопки OPTIONS
содержит следующие заголовки:
Общие заголовки
Request URL: https://cors3.azurewebsites.net/api/TodoItems2/MyDelete2/5
Request Method: OPTIONS
Status Code: 204 No Content
Заголовки ответа
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
Заголовки запроса
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
В предыдущих заголовках ответа сервер задает заголовок Access-Control-Allow-Origin в ответе. Значение https://cors1.azurewebsites.net
этого заголовка соответствует заголовку Origin
из запроса.
Если AllowAnyOrigin вызывается, Access-Control-Allow-Origin: *
возвращается подстановочное значение. AllowAnyOrigin
разрешает любой источник.
Если ответ не включает Access-Control-Allow-Origin
заголовок, запрос между источниками завершается ошибкой. В частности, браузер запрещает запрос. Даже если сервер возвращает успешный ответ, браузер не делает ответ доступным для клиентского приложения.
Запросы к конечной точке с использованием HTTP, перенаправленных на HTTPS, сбоем UseHttpsRedirection ERR_INVALID_REDIRECT on the CORS preflight request
.
Проекты API могут отклонять HTTP-запросы, а не использовать UseHttpsRedirection
для перенаправления запросов на HTTPS.
При развертывании в IIS CORS необходимо запустить перед проверкой подлинности Windows, если сервер не настроен для предоставления анонимного доступа. Для поддержки этого сценария необходимо установить и настроить модуль IIS CORS для приложения.
Пример скачивания содержит код для тестирования CORS. См. раздел Практическое руководство. Скачивание файла. Примером является проект API с 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();
Предупреждение
WithOrigins("https://localhost:<port>");
следует использовать только для тестирования примера приложения, аналогичного примеру кода скачивания.
ValuesController
Ниже приведены конечные точки для тестирования:
[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 предоставляется пакетом NuGet Rick.Docs.Samples.RouteInfo и отображает информацию о маршруте.
Протестируйте предыдущий пример кода с помощью одного из следующих подходов:
dotnet run
использованием URL-адреса https://localhost:5001
по умолчанию.https://localhost:44398
.Использование браузера с инструментами F12:
Нажмите кнопку "Значения" и просмотрите заголовки на вкладке "Сеть".
Нажмите кнопку "Тест PUT ". Сведения о отображении запроса OPTIONS см. в разделе "Запросы ПАРАМЕТРОВ ". Тест PUT создает два запроса, предварительный запрос OPTIONS и запрос PUT.
Нажмите кнопку GetValues2 [DisableCors]
, чтобы активировать неудачный запрос CORS. Как упоминалось в документе, ответ возвращает 200 успешно, но запрос CORS не выполняется. Перейдите на вкладку "Консоль", чтобы увидеть ошибку CORS. В зависимости от браузера отображается ошибка, аналогичная следующему:
Доступ к получению 'https://cors1.azurewebsites.net/api/values/GetValues2'
из источника 'https://cors3.azurewebsites.net'
заблокирован политикой CORS: в запрошенном ресурсе отсутствует заголовок Access-Control-Allow-Origin. Если этот непрозрачный ответ вам подходит, задайте для режима запроса значение "no-cors", чтобы извлечь ресурс с отключенным параметром CORS.
Конечные точки с поддержкой CORS можно протестировать с помощью средства, например curl или Fiddler. При использовании средства источник запроса, указанного Origin
заголовком, должен отличаться от узла, получающего запрос. Если запрос не является кросс-источником на основе значения заголовка Origin
:
Следующая команда используется curl
для выдачи запроса OPTIONS с информацией:
curl -X OPTIONS https://cors3.azurewebsites.net/api/TodoItems2/5 -i
Рассмотрим следующий код, который использует маршрутизацию конечных точек для включения CORS на основе каждой конечной точки с помощью 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();
Обратите внимание, что только /echo
конечная точка используется RequireCors
для разрешения запросов между источниками с помощью указанной политики. Приведенные ниже контроллеры позволяют CORS использовать атрибут [EnableCors].
TodoItems1Controller
Ниже приведены конечные точки для тестирования:
[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);
}
Кнопки Delete [EnableCors] и GET [EnableCors] успешно выполнены, так как конечные точки имеют [EnableCors]
и отвечают на предварительные запросы. Сбой других конечных точек. Кнопка GET завершается ошибкой, так как JavaScript отправляет:
headers: {
"Content-Type": "x-custom-header"
},
TodoItems2Controller
Ниже приведены аналогичные конечные точки, но содержит явный код для реагирования на запросы 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);
}
Приведенный выше код можно проверить, развернув пример, чтобы Azure.In раскрывающемся списке контроллера , выберите предварительный просмотр и установите контроллер. Все вызовы CORS к TodoItems2Controller
конечным точкам успешно выполнены.
Авторы: Рик Андерсон (Rick Anderson) и Кирк Ларкин (Kirk Larkin)
В этой статье показано, как включить CORS в приложении ASP.NET Core.
Система безопасности браузера предотвращает запросы веб-страницы к другому домену, отличному от того, который обслуживает веб-страницу. Это ограничение называется политика одного источника. Эта политика предотвращает чтение вредоносным сайтом конфиденциальных данных с другого сайта. Иногда вы должны разрешить другим сайтам выполнять запросы к приложению независимо от источника. Дополнительные сведения см. в статье Mozilla CORS.
Общий доступ к ресурсам между источниками (CORS):
Просмотреть или скачать образец кода (описание загрузки)
Два URL-адреса имеют одинаковый источник, если они имеют одинаковые схемы, узлы и порты (RFC 6454).
Эти два URL-адреса имеют одинаковый источник:
https://example.com/foo.html
https://example.com/bar.html
Эти URL-адреса имеют разные источники, отличные от предыдущих двух URL-адресов:
https://example.net
: другой доменhttps://www.example.com/foo.html
: другой поддоменhttp://example.com/foo.html
: другая схемаhttps://example.com:9000/foo.html
: другой портСуществует три способа включения CORS:
Использование атрибута [EnableCors] с именованной политикой обеспечивает лучший контроль в ограничении конечных точек, поддерживающих CORS.
Предупреждение
UseCors должен вызываться в правильном порядке. Дополнительные сведения см. в порядке по промежуточного слоя. Например, UseCors
необходимо вызвать перед UseResponseCaching использованием UseResponseCaching
.
Каждый подход подробно описан в следующих разделах.
ПО промежуточного слоя CORS обрабатывает запросы между источниками. Следующий код применяет политику CORS ко всем конечным точкам приложения с указанными источниками:
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();
Предыдущий код:
_myAllowSpecificOrigins
имени политики значение . Имя политики является произвольным._myAllowSpecificOrigins
политику CORS. UseCors
добавляет ПО промежуточного слоя CORS. UseCors
Вызов должен быть помещен после UseRouting
, но до UseAuthorization
. Дополнительные сведения см. в порядке по промежуточного слоя.WithOrigins
, описаны далее в этой статье._myAllowSpecificOrigins
Включает политику CORS для всех конечных точек контроллера. См. маршрутизацию конечных точек, чтобы применить политику CORS к определенным конечным точкам.При маршрутизации конечных точек ПО промежуточного слоя CORS необходимо настроить для выполнения между вызовами UseRouting
и UseEndpoints
.
Вызов AddCors метода добавляет службы CORS в контейнер службы приложения:
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();
Дополнительные сведения см. в разделе "Параметры политики CORS" в этом документе.
Методы CorsPolicyBuilder можно связать, как показано в следующем коде:
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();
Примечание. Указанный URL-адрес не должен содержать косую черту (/
). Если URL-адрес завершается /
, сравнение возвращается false
и заголовок не возвращается.
Предупреждение
UseCors
должно быть помещено после UseRouting
и до UseAuthorization
. Это позволяет убедиться, что заголовки CORS включены в ответ как для авторизованных, так и для несанкционированных вызовов.
Как правило, UseStaticFiles
вызывается раньше UseCors
. Приложения, использующие JavaScript для получения статических файлов, должны вызываться перед UseStaticFiles
вызовомUseCors
.
Следующий выделенный код включает политику 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();
Приведенный выше код применяет политику CORS по умолчанию ко всем конечным точкам контроллера.
Включение CORS на основе каждой конечной точки не RequireCors
поддерживает автоматические предварительные запросы. Дополнительные сведения см. в этой проблеме GitHub и тестировании CORS с маршрутизацией конечных точек и [HttpOptions].
При маршрутизации конечных точек CORS можно включить на основе каждой конечной точки с помощью RequireCors набора методов расширения:
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();
В предыдущем коде:
app.UseCors
включает ПО промежуточного слоя CORS. Так как политика по умолчанию не настроена, app.UseCors()
только не включает CORS./echo
точки и конечные точки контроллера разрешают запросы между источниками с помощью указанной политики./echo2
точки и Razor страницы не разрешают запросы между источниками, так как политика по умолчанию не указана.Атрибут [DisableCors] не отключает CORS, включенную маршрутизацией конечных точек.RequireCors
Ознакомьтесь с инструкциями по тестированию CORS с маршрутизацией конечных точек и [HttpOptions] , как показано выше.
Включение CORS с атрибутом [EnableCors] и применение именованной политики только к тем конечным точкам, которым требуется CORS, обеспечивает лучший контроль.
Атрибут [EnableCors] предоставляет альтернативу применению CORS глобально. Атрибут [EnableCors]
включает CORS для выбранных конечных точек, а не для всех конечных точек:
[EnableCors]
указывает политику по умолчанию.[EnableCors("{Policy String}")]
указывает именованную политику.Атрибут [EnableCors]
можно применить к:
PageModel
Различные политики можно применять к контроллерам, моделям страниц или методам действий с атрибутом [EnableCors]
. [EnableCors]
Если атрибут применяется к контроллеру, модели страницы или методу действия, а CORS включен в ПО промежуточного слоя, применяются обе политики. Рекомендуется объединять политики. Используйте[EnableCors]
атрибут или ПО промежуточного слоя, а не в одном приложении.
Следующий код применяет другую политику к каждому методу:
[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(),
};
}
}
Следующий код создает две политики 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();
Для лучшего контроля ограничения запросов CORS:
[EnableCors("MyPolicy")]
с именованной политикой.Код в следующем разделе соответствует предыдущему списку.
Атрибут [DisableCors] не отключает CORS, включенную маршрутизацией конечных точек.
Следующий код определяет политику "MyPolicy"
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();
Следующий код отключает CORS для GetValues2
действия:
[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();
}
Предыдущий код:
"MyPolicy"
политики CORS для контроллера.GetValues2
метода.Сведения о тестировании предыдущего кода см. в разделе Test CORS .
В этом разделе описаны различные параметры, которые можно задать в политике CORS:
AddPolicy вызывается в Program.cs
. Для некоторых вариантов может быть полезно сначала ознакомиться с разделом о работе CORS.
AllowAnyOrigin: разрешает запросы CORS из всех источников с любой схемой (http
или https
). AllowAnyOrigin
небезопасно, так как любой веб-сайт может выполнять запросы между источниками приложения.
Примечание
Указание AllowAnyOrigin
и AllowCredentials
является небезопасной конфигурацией и может привести к подделке межсайтовых запросов. Служба CORS возвращает недопустимый ответ CORS, если приложение настроено с использованием обоих методов.
AllowAnyOrigin
влияет на предварительные Access-Control-Allow-Origin
запросы и заголовок. Дополнительные сведения см. в разделе "Предварительные запросы ".
SetIsOriginAllowedToAllowWildcardSubdomains: задает IsOriginAllowed свойство политики, которая позволяет источникам сопоставлять настроенный домен подстановочных знаков при оценке допустимости источника.
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();
Access-Control-Allow-Methods
запросы и заголовок. Дополнительные сведения см. в разделе "Предварительные запросы ".Чтобы разрешить отправку определенных заголовков в запросе CORS, называется заголовками запросов автора, вызовом WithHeaders и указанием разрешенных заголовков:
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();
Чтобы разрешить все заголовки запросов автора, вызовите 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
влияет на предварительные запросы и заголовок Access-Control-Request-Headers . Дополнительные сведения см. в разделе "Предварительные запросы ".
Политика ПО промежуточного слоя CORS соответствует определенным заголовкам, указанным WithHeaders
только в том случае, если заголовки, отправленные точно Access-Control-Request-Headers
соответствуют заголовкам, указанным в .WithHeaders
Например, рассмотрим приложение, настроенное следующим образом:
app.UseCors(policy => policy.WithHeaders(HeaderNames.CacheControl));
ПО промежуточного слоя CORS отклоняет предварительный запрос со следующим заголовком запроса, так как Content-Language
(HeaderNames.ContentLanguage) не указан вWithHeaders
:
Access-Control-Request-Headers: Cache-Control, Content-Language
Приложение возвращает ответ 200 OK , но не отправляет заголовки CORS обратно. Поэтому браузер не пытается выполнить запрос между источниками.
По умолчанию браузер не предоставляет все заголовки ответа приложению. Дополнительные сведения см. в разделе "Общий доступ к ресурсам между источниками W3C" (терминология): простой заголовок ответа.
Заголовки ответов, доступные по умолчанию:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
Спецификация CORS вызывает эти заголовки простых заголовков ответа. Чтобы сделать другие заголовки доступными для приложения, вызовите 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();
Учетные данные требуют специальной обработки в запросе CORS. По умолчанию браузер не отправляет учетные данные с запросом между источниками. Учетные данные включают файлы cookie и схемы проверки подлинности HTTP. Чтобы отправить учетные данные с запросом между источниками, клиент должен задать значение XMLHttpRequest.withCredentials
true
.
Использование XMLHttpRequest
напрямую:
var xhr = new XMLHttpRequest();
xhr.open('get', 'https://www.example.com/api/test');
xhr.withCredentials = true;
Использование jQuery:
$.ajax({
type: 'get',
url: 'https://www.example.com/api/test',
xhrFields: {
withCredentials: true
}
});
Использование API получения:
fetch('https://www.example.com/api/test', {
credentials: 'include'
});
Сервер должен разрешить учетные данные. Чтобы разрешить учетные данные между источниками, вызовите 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();
Http-ответ содержит заголовок, который сообщает браузеру Access-Control-Allow-Credentials
, что сервер разрешает учетные данные для запроса между источниками.
Если браузер отправляет учетные данные, но ответ не содержит допустимый Access-Control-Allow-Credentials
заголовок, браузер не предоставляет ответ приложению, а запрос между источниками завершается ошибкой.
Разрешение учетных данных между источниками — это риск безопасности. Веб-сайт в другом домене может отправлять учетные данные пользователя, выполнившего вход, в приложение от имени пользователя без знаний пользователя.
Спецификация CORS также указывает, что установка источников "*"
(всех источников) недопустима, если заголовок Access-Control-Allow-Credentials
присутствует.
Для некоторых запросов CORS браузер отправляет дополнительный запрос OPTIONS перед выполнением фактического запроса. Этот запрос называется предварительным запросом. Браузер может пропустить предварительный запрос, если выполняются все следующие условия:
Accept
, Accept-Language
, , Content-Language
Content-Type
или Last-Event-ID
.Content-Type
, если задано, имеет одно из следующих значений: application/x-www-form-urlencoded
multipart/form-data
text/plain
Правило заголовков запросов, заданных для клиентского запроса, применяется к заголовкам, заданным приложением путем вызова setRequestHeader
XMLHttpRequest
объекта. Спецификация CORS вызывает эти заголовки для создания запросов. Правило не применяется к заголовкам, которые браузер может задать, например User-Agent
, Host
или Content-Length
.
Ниже приведен пример ответа, аналогичного запросу предварительной проверки, сделанному на кнопке [Put test] в разделе Test CORS этого документа.
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
Предварительный запрос использует метод HTTP OPTIONS . Он может включать следующие заголовки:
User-Agent
.Если запрос на предварительную 200 OK
проверку запрещен, приложение возвращает ответ, но не задает заголовки CORS. Поэтому браузер не пытается выполнить запрос между источниками. Пример отклоненного предварительного запроса см. в разделе test CORS этого документа.
С помощью средств F12 консольное приложение отображает ошибку, аналогичную одной из следующих, в зависимости от браузера:
https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5
. (Причина: запрос CORS не выполнен). ПодробнееЧтобы разрешить определенные заголовки, вызовите 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();
Чтобы разрешить все заголовки запросов автора, вызовите 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();
Браузеры не согласованы в том, как они заданы Access-Control-Request-Headers
. Если одно из следующих вариантов:
"*"
Accept
, Content-Type
и Origin
, а также все пользовательские заголовки, которые требуется поддерживать.При применении политики CORS:
app.UseCors
Program.cs
.[EnableCors]
.ASP.NET Core отвечает на запрос параметров предварительной проверки.
Включение CORS на основе каждой конечной точки с использованием RequireCors
в настоящее время не поддерживает автоматические предварительные запросы.
В разделе Test CORS этого документа показано это поведение.
Если CORS включена с соответствующей политикой, ASP.NET Core обычно реагирует на запросы предварительной проверки CORS автоматически. В некоторых сценариях это может быть не так. Например, использование CORS с маршрутизацией конечных точек.
Следующий код использует атрибут [HttpOptions] для создания конечных точек для запросов 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);
}
Инструкции по тестированию предыдущего кода см. в разделе Test CORS с маршрутизацией конечных точек и [HttpOptions] .
Заголовок Access-Control-Max-Age
указывает, сколько времени можно кэшировать ответ на предварительный запрос. Чтобы задать этот заголовок, вызовите 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();
В этом разделе описывается, что происходит в запросе CORS на уровне HTTP-сообщений.
<script>
тег для получения ответа. Скрипты могут загружаться между источниками.Спецификация CORS представила несколько новых заголовков HTTP, которые позволяют выполнять запросы между источниками. Если браузер поддерживает CORS, он автоматически задает эти заголовки для запросов между источниками. Пользовательский код JavaScript не требуется для включения CORS.
Ниже приведен пример запроса между источниками из кнопки "Тест значений " в https://cors1.azurewebsites.net/api/values
. Заголовок Origin
:
Общие заголовки
Request URL: https://cors1.azurewebsites.net/api/values
Request Method: GET
Status Code: 200 OK
Заголовки ответа
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
Заголовки запроса
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 ...
В OPTIONS
запросах сервер задает заголовок заголовков Access-Control-Allow-Origin: {allowed origin}
ответа в ответе. Например, развернутый пример запроса кнопки OPTIONS
Delete [EnableCors] содержит следующие заголовки:
Общие заголовки
Request URL: https://cors3.azurewebsites.net/api/TodoItems2/MyDelete2/5
Request Method: OPTIONS
Status Code: 204 No Content
Заголовки ответа
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
Заголовки запроса
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
В предыдущих заголовках ответа сервер задает заголовок Access-Control-Allow-Origin в ответе. Значение https://cors1.azurewebsites.net
этого заголовка соответствует заголовку Origin
из запроса.
Если AllowAnyOrigin вызывается, Access-Control-Allow-Origin: *
возвращается подстановочное значение. AllowAnyOrigin
разрешает любой источник.
Если ответ не включает Access-Control-Allow-Origin
заголовок, запрос между источниками завершается ошибкой. В частности, браузер запрещает запрос. Даже если сервер возвращает успешный ответ, браузер не делает ответ доступным для клиентского приложения.
Запросы к конечной точке с использованием HTTP, перенаправленных на HTTPS, сбоем UseHttpsRedirection ERR_INVALID_REDIRECT on the CORS preflight request
.
Проекты API могут отклонять HTTP-запросы, а не использовать UseHttpsRedirection
для перенаправления запросов на HTTPS.
По умолчанию браузеры Chrome и Edge не отображают запросы OPTIONS на сетевой вкладке инструментов F12. Чтобы отобразить запросы OPTIONS в этих браузерах, выполните следующие действия.
chrome://flags/#out-of-blink-cors
или edge://flags/#out-of-blink-cors
Firefox отображает запросы OPTIONS по умолчанию.
При развертывании в IIS CORS необходимо запустить перед проверкой подлинности Windows, если сервер не настроен для предоставления анонимного доступа. Для поддержки этого сценария необходимо установить и настроить модуль IIS CORS для приложения.
Пример скачивания содержит код для тестирования CORS. См. раздел Практическое руководство. Скачивание файла. Примером является проект API с 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();
Предупреждение
WithOrigins("https://localhost:<port>");
следует использовать только для тестирования примера приложения, аналогичного примеру кода скачивания.
ValuesController
Ниже приведены конечные точки для тестирования:
[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 предоставляется пакетом NuGet Rick.Docs.Samples.RouteInfo и отображает информацию о маршруте.
Протестируйте предыдущий пример кода с помощью одного из следующих подходов:
dotnet run
использованием URL-адреса https://localhost:5001
по умолчанию.https://localhost:44398
.Использование браузера с инструментами F12:
Нажмите кнопку "Значения" и просмотрите заголовки на вкладке "Сеть".
Нажмите кнопку "Тест PUT ". Сведения о отображении запроса OPTIONS см. в разделе "Запросы ПАРАМЕТРОВ ". Тест PUT создает два запроса, предварительный запрос OPTIONS и запрос PUT.
Нажмите кнопку GetValues2 [DisableCors]
, чтобы активировать неудачный запрос CORS. Как упоминалось в документе, ответ возвращает 200 успешно, но запрос CORS не выполняется. Перейдите на вкладку "Консоль", чтобы увидеть ошибку CORS. В зависимости от браузера отображается ошибка, аналогичная следующему:
Доступ к получению 'https://cors1.azurewebsites.net/api/values/GetValues2'
из источника 'https://cors3.azurewebsites.net'
заблокирован политикой CORS: в запрошенном ресурсе отсутствует заголовок Access-Control-Allow-Origin. Если этот непрозрачный ответ вам подходит, задайте для режима запроса значение "no-cors", чтобы извлечь ресурс с отключенным параметром CORS.
Конечные точки с поддержкой CORS можно протестировать с помощью средства, например curl или Fiddler. При использовании средства источник запроса, указанного Origin
заголовком, должен отличаться от узла, получающего запрос. Если запрос не является кросс-источником на основе значения заголовка Origin
:
Следующая команда используется curl
для выдачи запроса OPTIONS с информацией:
curl -X OPTIONS https://cors3.azurewebsites.net/api/TodoItems2/5 -i
Включение CORS на основе каждой конечной точки с использованием RequireCors
в настоящее время не поддерживает автоматические предварительные запросы. Рассмотрим следующий код, использующий маршрутизацию конечных точек для включения 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();
TodoItems1Controller
Ниже приведены конечные точки для тестирования:
[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);
}
Проверьте предыдущий код на тестовой странице (https://cors1.azurewebsites.net/test?number=1
) развернутого примера.
Кнопки Delete [EnableCors] и GET [EnableCors] успешно выполнены, так как конечные точки имеют [EnableCors]
и отвечают на предварительные запросы. Сбой других конечных точек. Кнопка GET завершается ошибкой, так как JavaScript отправляет:
headers: {
"Content-Type": "x-custom-header"
},
TodoItems2Controller
Ниже приведены аналогичные конечные точки, но содержит явный код для реагирования на запросы 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);
}
Приведенный выше код можно проверить, развернув пример, чтобы Azure.In раскрывающемся списке контроллера , выберите предварительный просмотр и установите контроллер. Все вызовы CORS к TodoItems2Controller
конечным точкам успешно выполнены.
Авторы: Рик Андерсон (Rick Anderson) и Кирк Ларкин (Kirk Larkin)
В этой статье показано, как включить CORS в приложении ASP.NET Core.
Система безопасности браузера предотвращает запросы веб-страницы к другому домену, отличному от того, который обслуживает веб-страницу. Это ограничение называется политика одного источника. Эта политика предотвращает чтение вредоносным сайтом конфиденциальных данных с другого сайта. Иногда вы должны разрешить другим сайтам выполнять запросы к приложению независимо от источника. Дополнительные сведения см. в статье Mozilla CORS.
Общий доступ к ресурсам между источниками (CORS):
Просмотреть или скачать образец кода (описание загрузки)
Два URL-адреса имеют одинаковый источник, если они имеют одинаковые схемы, узлы и порты (RFC 6454).
Эти два URL-адреса имеют одинаковый источник:
https://example.com/foo.html
https://example.com/bar.html
Эти URL-адреса имеют разные источники, отличные от предыдущих двух URL-адресов:
https://example.net
: другой доменhttps://www.example.com/foo.html
: другой поддоменhttp://example.com/foo.html
: другая схемаhttps://example.com:9000/foo.html
: другой портСуществует три способа включения CORS:
Использование атрибута [EnableCors] с именованной политикой обеспечивает лучший контроль в ограничении конечных точек, поддерживающих CORS.
Предупреждение
UseCors должен вызываться в правильном порядке. Дополнительные сведения см. в порядке по промежуточного слоя. Например, UseCors
необходимо вызвать перед UseResponseCaching использованием UseResponseCaching
.
Каждый подход подробно описан в следующих разделах.
ПО промежуточного слоя CORS обрабатывает запросы между источниками. Следующий код применяет политику CORS ко всем конечным точкам приложения с указанными источниками:
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();
});
}
}
Предыдущий код:
_myAllowSpecificOrigins
имени политики значение . Имя политики является произвольным._myAllowSpecificOrigins
политику CORS. UseCors
добавляет ПО промежуточного слоя CORS. UseCors
Вызов должен быть помещен после UseRouting
, но до UseAuthorization
. Дополнительные сведения см. в порядке по промежуточного слоя.WithOrigins
, описаны далее в этой статье._myAllowSpecificOrigins
Включает политику CORS для всех конечных точек контроллера. См. маршрутизацию конечных точек, чтобы применить политику CORS к определенным конечным точкам.При маршрутизации конечных точек ПО промежуточного слоя CORS необходимо настроить для выполнения между вызовами UseRouting
и UseEndpoints
.
Ознакомьтесь с инструкциями по тестированию кода, аналогичного приведенному выше.
Вызов AddCors метода добавляет службы CORS в контейнер службы приложения:
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();
}
Дополнительные сведения см. в разделе "Параметры политики CORS" в этом документе.
Методы CorsPolicyBuilder можно связать, как показано в следующем коде:
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();
}
Примечание. Указанный URL-адрес не должен содержать косую черту (/
). Если URL-адрес завершается /
, сравнение возвращается false
и заголовок не возвращается.
Следующий выделенный код включает политику 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();
});
}
}
Приведенный выше код применяет политику CORS по умолчанию ко всем конечным точкам контроллера.
Включение CORS на основе каждой конечной точки не RequireCors
поддерживает автоматические предварительные запросы. Дополнительные сведения см. в этой проблеме GitHub и тестировании CORS с маршрутизацией конечных точек и [HttpOptions].
При маршрутизации конечных точек CORS можно включить на основе каждой конечной точки с помощью RequireCors набора методов расширения:
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();
});
}
}
В предыдущем коде:
app.UseCors
включает ПО промежуточного слоя CORS. Так как политика по умолчанию не настроена, app.UseCors()
только не включает CORS./echo
точки и конечные точки контроллера разрешают запросы между источниками с помощью указанной политики./echo2
точки и Razor страницы не разрешают запросы между источниками, так как политика по умолчанию не указана.Атрибут [DisableCors] не отключает CORS, включенную маршрутизацией конечных точек.RequireCors
Ознакомьтесь с инструкциями по тестированию CORS с маршрутизацией конечных точек и [HttpOptions] , как показано выше.
Включение CORS с атрибутом [EnableCors] и применение именованной политики только к тем конечным точкам, которым требуется CORS, обеспечивает лучший контроль.
Атрибут [EnableCors] предоставляет альтернативу применению CORS глобально. Атрибут [EnableCors]
включает CORS для выбранных конечных точек, а не для всех конечных точек:
[EnableCors]
указывает политику по умолчанию.[EnableCors("{Policy String}")]
указывает именованную политику.Атрибут [EnableCors]
можно применить к:
PageModel
Различные политики можно применять к контроллерам, моделям страниц или методам действий с атрибутом [EnableCors]
. [EnableCors]
Если атрибут применяется к контроллеру, модели страницы или методу действия, а CORS включен в ПО промежуточного слоя, применяются обе политики. Рекомендуется объединять политики. Используйте[EnableCors]
атрибут или ПО промежуточного слоя, а не в одном приложении.
Следующий код применяет другую политику к каждому методу:
[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(),
};
}
}
Следующий код создает две политики 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();
});
}
}
Для лучшего контроля ограничения запросов CORS:
[EnableCors("MyPolicy")]
с именованной политикой.Код в следующем разделе соответствует предыдущему списку.
Ознакомьтесь с инструкциями по тестированию кода, аналогичного приведенному выше.
Атрибут [DisableCors] не отключает CORS, включенную маршрутизацией конечных точек.
Следующий код определяет политику "MyPolicy"
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();
});
}
}
Следующий код отключает CORS для GetValues2
действия:
[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();
}
Предыдущий код:
"MyPolicy"
политики CORS для контроллера.GetValues2
метода.Сведения о тестировании предыдущего кода см. в разделе Test CORS .
В этом разделе описаны различные параметры, которые можно задать в политике CORS:
AddPolicy вызывается в Startup.ConfigureServices
. Для некоторых вариантов может быть полезно сначала ознакомиться с разделом о работе CORS.
AllowAnyOrigin: разрешает запросы CORS из всех источников с любой схемой (http
или https
). AllowAnyOrigin
небезопасно, так как любой веб-сайт может выполнять запросы между источниками приложения.
Примечание
Указание AllowAnyOrigin
и AllowCredentials
является небезопасной конфигурацией и может привести к подделке межсайтовых запросов. Служба CORS возвращает недопустимый ответ CORS, если приложение настроено с использованием обоих методов.
AllowAnyOrigin
влияет на предварительные Access-Control-Allow-Origin
запросы и заголовок. Дополнительные сведения см. в разделе "Предварительные запросы ".
SetIsOriginAllowedToAllowWildcardSubdomains: задает IsOriginAllowed свойство политики, которая позволяет источникам сопоставлять настроенный домен подстановочных знаков при оценке допустимости источника.
options.AddPolicy("MyAllowSubdomainPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.SetIsOriginAllowedToAllowWildcardSubdomains();
});
Access-Control-Allow-Methods
запросы и заголовок. Дополнительные сведения см. в разделе "Предварительные запросы ".Чтобы разрешить отправку определенных заголовков в запросе CORS, называется заголовками запросов автора, вызовом WithHeaders и указанием разрешенных заголовков:
options.AddPolicy("MyAllowHeadersPolicy",
policy =>
{
// requires using Microsoft.Net.Http.Headers;
policy.WithOrigins("http://example.com")
.WithHeaders(HeaderNames.ContentType, "x-custom-header");
});
Чтобы разрешить все заголовки запросов автора, вызовите AllowAnyHeader:
options.AddPolicy("MyAllowAllHeadersPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.AllowAnyHeader();
});
AllowAnyHeader
влияет на предварительные запросы и заголовок Access-Control-Request-Headers . Дополнительные сведения см. в разделе "Предварительные запросы ".
Политика ПО промежуточного слоя CORS соответствует определенным заголовкам, указанным WithHeaders
только в том случае, если заголовки, отправленные точно Access-Control-Request-Headers
соответствуют заголовкам, указанным в .WithHeaders
Например, рассмотрим приложение, настроенное следующим образом:
app.UseCors(policy => policy.WithHeaders(HeaderNames.CacheControl));
ПО промежуточного слоя CORS отклоняет предварительный запрос со следующим заголовком запроса, так как Content-Language
(HeaderNames.ContentLanguage) не указан вWithHeaders
:
Access-Control-Request-Headers: Cache-Control, Content-Language
Приложение возвращает ответ 200 OK , но не отправляет заголовки CORS обратно. Поэтому браузер не пытается выполнить запрос между источниками.
По умолчанию браузер не предоставляет все заголовки ответа приложению. Дополнительные сведения см. в разделе "Общий доступ к ресурсам между источниками W3C" (терминология): простой заголовок ответа.
Заголовки ответов, доступные по умолчанию:
Cache-Control
Content-Language
Content-Type
Expires
Last-Modified
Pragma
Спецификация CORS вызывает эти заголовки простых заголовков ответа. Чтобы сделать другие заголовки доступными для приложения, вызовите WithExposedHeaders:
options.AddPolicy("MyExposeResponseHeadersPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.WithExposedHeaders("x-custom-header");
});
Учетные данные требуют специальной обработки в запросе CORS. По умолчанию браузер не отправляет учетные данные с запросом между источниками. Учетные данные включают файлы cookie и схемы проверки подлинности HTTP. Чтобы отправить учетные данные с запросом между источниками, клиент должен задать значение XMLHttpRequest.withCredentials
true
.
Использование XMLHttpRequest
напрямую:
var xhr = new XMLHttpRequest();
xhr.open('get', 'https://www.example.com/api/test');
xhr.withCredentials = true;
Использование jQuery:
$.ajax({
type: 'get',
url: 'https://www.example.com/api/test',
xhrFields: {
withCredentials: true
}
});
Использование API получения:
fetch('https://www.example.com/api/test', {
credentials: 'include'
});
Сервер должен разрешить учетные данные. Чтобы разрешить учетные данные между источниками, вызовите AllowCredentials:
options.AddPolicy("MyMyAllowCredentialsPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.AllowCredentials();
});
Http-ответ содержит заголовок, который сообщает браузеру Access-Control-Allow-Credentials
, что сервер разрешает учетные данные для запроса между источниками.
Если браузер отправляет учетные данные, но ответ не содержит допустимый Access-Control-Allow-Credentials
заголовок, браузер не предоставляет ответ приложению, а запрос между источниками завершается ошибкой.
Разрешение учетных данных между источниками — это риск безопасности. Веб-сайт в другом домене может отправлять учетные данные пользователя, выполнившего вход, в приложение от имени пользователя без знаний пользователя.
Спецификация CORS также указывает, что установка источников "*"
(всех источников) недопустима, если заголовок Access-Control-Allow-Credentials
присутствует.
Для некоторых запросов CORS браузер отправляет дополнительный запрос OPTIONS перед выполнением фактического запроса. Этот запрос называется предварительным запросом. Браузер может пропустить предварительный запрос, если выполняются все следующие условия:
Accept
, Accept-Language
, , Content-Language
Content-Type
или Last-Event-ID
.Content-Type
, если задано, имеет одно из следующих значений: application/x-www-form-urlencoded
multipart/form-data
text/plain
Правило заголовков запросов, заданных для клиентского запроса, применяется к заголовкам, заданным приложением путем вызова setRequestHeader
XMLHttpRequest
объекта. Спецификация CORS вызывает эти заголовки для создания запросов. Правило не применяется к заголовкам, которые браузер может задать, например User-Agent
, Host
или Content-Length
.
Ниже приведен пример ответа, аналогичного запросу предварительной проверки, сделанному на кнопке [Put test] в разделе Test CORS этого документа.
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
Предварительный запрос использует метод HTTP OPTIONS . Он может включать следующие заголовки:
User-Agent
.Если запрос на предварительную 200 OK
проверку запрещен, приложение возвращает ответ, но не задает заголовки CORS. Поэтому браузер не пытается выполнить запрос между источниками. Пример отклоненного предварительного запроса см. в разделе test CORS этого документа.
С помощью средств F12 консольное приложение отображает ошибку, аналогичную одной из следующих, в зависимости от браузера:
https://cors1.azurewebsites.net/api/TodoItems1/MyDelete2/5
. (Причина: запрос CORS не выполнен). ПодробнееЧтобы разрешить определенные заголовки, вызовите WithHeaders:
options.AddPolicy("MyAllowHeadersPolicy",
policy =>
{
// requires using Microsoft.Net.Http.Headers;
policy.WithOrigins("http://example.com")
.WithHeaders(HeaderNames.ContentType, "x-custom-header");
});
Чтобы разрешить все заголовки запросов автора, вызовите AllowAnyHeader:
options.AddPolicy("MyAllowAllHeadersPolicy",
policy =>
{
policy.WithOrigins("https://*.example.com")
.AllowAnyHeader();
});
Браузеры не согласованы в том, как они заданы Access-Control-Request-Headers
. Если одно из следующих вариантов:
"*"
Accept
, Content-Type
и Origin
, а также все пользовательские заголовки, которые требуется поддерживать.При применении политики CORS:
app.UseCors
Startup.Configure
.[EnableCors]
.ASP.NET Core отвечает на запрос параметров предварительной проверки.
Включение CORS на основе каждой конечной точки с использованием RequireCors
в настоящее время не поддерживает автоматические предварительные запросы.
В разделе Test CORS этого документа показано это поведение.
Если CORS включена с соответствующей политикой, ASP.NET Core обычно реагирует на запросы предварительной проверки CORS автоматически. В некоторых сценариях это может быть не так. Например, использование CORS с маршрутизацией конечных точек.
Следующий код использует атрибут [HttpOptions] для создания конечных точек для запросов 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);
}
Инструкции по тестированию предыдущего кода см. в разделе Test CORS с маршрутизацией конечных точек и [HttpOptions] .
Заголовок Access-Control-Max-Age
указывает, сколько времени можно кэшировать ответ на предварительный запрос. Чтобы задать этот заголовок, вызовите SetPreflightMaxAge:
options.AddPolicy("MySetPreflightExpirationPolicy",
policy =>
{
policy.WithOrigins("http://example.com")
.SetPreflightMaxAge(TimeSpan.FromSeconds(2520));
});
В этом разделе описывается, что происходит в запросе CORS на уровне HTTP-сообщений.
<script>
тег для получения ответа. Скрипты могут загружаться между источниками.Спецификация CORS представила несколько новых заголовков HTTP, которые позволяют выполнять запросы между источниками. Если браузер поддерживает CORS, он автоматически задает эти заголовки для запросов между источниками. Пользовательский код JavaScript не требуется для включения CORS.
Ниже приведен пример запроса между источниками из кнопки "Тест значений " в https://cors1.azurewebsites.net/api/values
. Заголовок Origin
:
Общие заголовки
Request URL: https://cors1.azurewebsites.net/api/values
Request Method: GET
Status Code: 200 OK
Заголовки ответа
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
Заголовки запроса
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 ...
В OPTIONS
запросах сервер задает заголовок заголовков Access-Control-Allow-Origin: {allowed origin}
ответа в ответе. Например, развернутый пример запроса кнопки OPTIONS
Delete [EnableCors] содержит следующие заголовки:
Общие заголовки
Request URL: https://cors3.azurewebsites.net/api/TodoItems2/MyDelete2/5
Request Method: OPTIONS
Status Code: 204 No Content
Заголовки ответа
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
Заголовки запроса
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
В предыдущих заголовках ответа сервер задает заголовок Access-Control-Allow-Origin в ответе. Значение https://cors1.azurewebsites.net
этого заголовка соответствует заголовку Origin
из запроса.
Если AllowAnyOrigin вызывается, Access-Control-Allow-Origin: *
возвращается подстановочное значение. AllowAnyOrigin
разрешает любой источник.
Если ответ не включает Access-Control-Allow-Origin
заголовок, запрос между источниками завершается ошибкой. В частности, браузер запрещает запрос. Даже если сервер возвращает успешный ответ, браузер не делает ответ доступным для клиентского приложения.
По умолчанию браузеры Chrome и Edge не отображают запросы OPTIONS на сетевой вкладке инструментов F12. Чтобы отобразить запросы OPTIONS в этих браузерах, выполните следующие действия.
chrome://flags/#out-of-blink-cors
или edge://flags/#out-of-blink-cors
Firefox отображает запросы OPTIONS по умолчанию.
При развертывании в IIS CORS необходимо запустить перед проверкой подлинности Windows, если сервер не настроен для предоставления анонимного доступа. Для поддержки этого сценария необходимо установить и настроить модуль IIS CORS для приложения.
Пример скачивания содержит код для тестирования CORS. См. раздел Практическое руководство. Скачивание файла. Примером является проект API с 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();
});
}
}
Предупреждение
WithOrigins("https://localhost:<port>");
следует использовать только для тестирования примера приложения, аналогичного примеру кода скачивания.
ValuesController
Ниже приведены конечные точки для тестирования:
[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 предоставляется пакетом NuGet Rick.Docs.Samples.RouteInfo и отображает информацию о маршруте.
Протестируйте предыдущий пример кода с помощью одного из следующих подходов:
dotnet run
использованием URL-адреса https://localhost:5001
по умолчанию.https://localhost:44398
.Использование браузера с инструментами F12:
Нажмите кнопку "Значения" и просмотрите заголовки на вкладке "Сеть".
Нажмите кнопку "Тест PUT ". Сведения о отображении запроса OPTIONS см. в разделе "Запросы ПАРАМЕТРОВ ". Тест PUT создает два запроса, предварительный запрос OPTIONS и запрос PUT.
Нажмите кнопку GetValues2 [DisableCors]
, чтобы активировать неудачный запрос CORS. Как упоминалось в документе, ответ возвращает 200 успешно, но запрос CORS не выполняется. Перейдите на вкладку "Консоль", чтобы увидеть ошибку CORS. В зависимости от браузера отображается ошибка, аналогичная следующему:
Доступ к получению 'https://cors1.azurewebsites.net/api/values/GetValues2'
из источника 'https://cors3.azurewebsites.net'
заблокирован политикой CORS: в запрошенном ресурсе отсутствует заголовок Access-Control-Allow-Origin. Если этот непрозрачный ответ вам подходит, задайте для режима запроса значение "no-cors", чтобы извлечь ресурс с отключенным параметром CORS.
Конечные точки с поддержкой CORS можно протестировать с помощью средства, например curl или Fiddler. При использовании средства источник запроса, указанного Origin
заголовком, должен отличаться от узла, получающего запрос. Если запрос не является кросс-источником на основе значения заголовка Origin
:
Следующая команда используется curl
для выдачи запроса OPTIONS с информацией:
curl -X OPTIONS https://cors3.azurewebsites.net/api/TodoItems2/5 -i
Включение CORS на основе каждой конечной точки с использованием RequireCors
в настоящее время не поддерживает автоматические предварительные запросы. Рассмотрим следующий код, использующий маршрутизацию конечных точек для включения 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();
});
}
}
TodoItems1Controller
Ниже приведены конечные точки для тестирования:
[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);
}
Проверьте предыдущий код на тестовой странице (https://cors1.azurewebsites.net/test?number=1
) развернутого примера.
Кнопки Delete [EnableCors] и GET [EnableCors] успешно выполнены, так как конечные точки имеют [EnableCors]
и отвечают на предварительные запросы. Сбой других конечных точек. Кнопка GET завершается ошибкой, так как JavaScript отправляет:
headers: {
"Content-Type": "x-custom-header"
},
TodoItems2Controller
Ниже приведены аналогичные конечные точки, но содержит явный код для реагирования на запросы 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);
}
Приведенный выше код можно проверить, развернув пример, чтобы Azure.In раскрывающемся списке контроллера , выберите предварительный просмотр и установите контроллер. Все вызовы CORS к TodoItems2Controller
конечным точкам успешно выполнены.
Отзыв о ASP.NET Core
ASP.NET Core — это проект с открытым исходным кодом. Выберите ссылку, чтобы оставить отзыв:
События
31 мар., 23 - 2 апр., 23
Конечное событие Power BI, Fabric, SQL и ai community. 31 марта – 2 апреля. Используйте код MSCUST для скидки на $150. Цены выросли на 11 февраля.
Зарегистрироваться сегодняОбучение
Модуль
Реализация операций HTTP в веб-приложениях ASP.NET Core Blazor Web - Training
Реализация операций HTTP в веб-приложениях ASP.NET Core Blazor Web