Включение CORS (Cross-Origin Resource Sharing) в Sisk
Эта страница переведена с английского автоматически. Читать оригинал
Sisk предоставляет инструмент, который может быть полезен для обработки Cross-Origin Resource Sharing (CORS) при публичном предоставлении вашего сервиса. Эта возможность не является частью протокола HTTP, а представляет собой специфическую функцию веб‑браузеров, определённую W3C. Этот механизм безопасности препятствует веб‑странице выполнять запросы к другому домену, отличному от того, с которого была получена сама страница. Поставщик сервиса может разрешить доступ к своим ресурсам определённым доменам или только одному.
Один и тот же источник #
Чтобы ресурс был идентифицирован как «один и тот же источник», запрос должен содержать заголовок Origin:
GET /api/users HTTP/1.1
Host: example.com
Origin: http://example.com
...А удалённый сервер должен ответить заголовком Access-Control-Allow-Origin со значением, совпадающим с запрошенным origin:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://example.com
...Эта проверка явная: хост, порт и протокол должны совпадать с запрошенными. Рассмотрим пример:
- Сервер отвечает, что его
Access-Control-Allow-Originравенhttps://example.com:https://example.net– домен отличается.http://example.com– схема отличается.http://example.com:5555– порт отличается.https://www.example.com– хост отличается.
В спецификации допускается только синтаксис для обоих заголовков, как для запросов, так и для ответов. Путь URL игнорируется. Порт также опускается, если он является портом по умолчанию (80 для HTTP и 443 для HTTPS).
Origin: null
Origin: <scheme>://<hostname>
Origin: <scheme>://<hostname>:<port>Включение CORS #
Нативно у вас есть объект CrossOriginResourceSharingHeaders внутри вашего ListeningHost.
Вы можете настроить CORS при инициализации сервера:
static async Task Main(string[] args)
{
using var app = HttpServer.CreateBuilder()
.UseCors(new CrossOriginResourceSharingHeaders(
allowOrigin: "http://example.com",
allowHeaders: ["Authorization"],
exposeHeaders: ["Content-Type"]))
.Build();
await app.StartAsync();
}Код выше отправит следующие заголовки для всех ответов:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://example.com
Access-Control-Allow-Headers: Authorization
Access-Control-Expose-Headers: Content-TypeЭти заголовки должны отправляться во всех ответах клиенту, включая ошибки и перенаправления.
Вы можете заметить, что класс CrossOriginResourceSharingHeaders имеет два похожих свойства: AllowOrigin и AllowOrigins. Обратите внимание, что одно — во множественном числе, другое — в единственном.
- Свойство AllowOrigin статично: только указанный вами origin будет отправлен во всех ответах.
- Свойство AllowOrigins динамично: сервер проверяет, содержится ли origin запроса в этом списке. Если найдено, он будет отправлен в ответе для данного origin.
Когда разрешённый origin зависит от запроса, то есть когда вы используете AllowOrigins или значение AutoAllowOrigin, описанное ниже, Sisk также добавляет заголовок Vary: Origin, чтобы кэши не переиспользовали ответ для другого origin.
Подстановочные знаки и автоматические заголовки #
В качестве альтернативы можно использовать подстановочный символ (*) в origin ответа, указывая, что любой origin разрешён для доступа к ресурсу. Однако такое значение недопустимо для запросов, содержащих учётные данные (заголовки авторизации), и такая операция приведёт к ошибке.
Обойти эту проблему можно, явно перечислив разрешённые origin через свойство AllowOrigins или используя константу AutoAllowOrigin в значении AllowOrigin. Это «магическое» свойство задаст заголовок Access-Control-Allow-Origin со значением, совпадающим с заголовком Origin запроса.
Также можно использовать AutoFromRequestMethod и AutoFromRequestHeaders для поведения, аналогичного AllowOrigin, которое автоматически отвечает на основе полученных заголовков.
using var host = HttpServer.CreateBuilder()
.UseCors(new CrossOriginResourceSharingHeaders(
// Отвечает в зависимости от заголовка Origin запроса
allowOrigin: CrossOriginResourceSharingHeaders.AutoAllowOrigin,
// Отвечает в зависимости от заголовка Access-Control-Request-Method или метода запроса
allowMethods: [CrossOriginResourceSharingHeaders.AutoFromRequestMethod],
// Отвечает в зависимости от заголовка Access-Control-Request-Headers или отправленных заголовков
allowHeaders: [CrossOriginResourceSharingHeaders.AutoFromRequestHeaders],
exposeHeaders: [HttpKnownHeaderNames.ContentType, "X-Authenticated-Account-Id"],
allowCredentials: true))
.Build();Другие способы применения CORS #
Если вы работаете с service providers, вы можете переопределить значения, определённые в файле конфигурации:
static async Task Main(string[] args)
{
using var app = HttpServer.CreateBuilder()
.UsePortableConfiguration(...)
.UseCors(cors => {
// Перезапишет origin, определённый в конфигурации
// файл.
cors.AllowOrigin = "http://example.com";
})
.Build();
await app.StartAsync();
}Отключение CORS на конкретных маршрутах #
Свойство UseCors доступно как для маршрутов, так и для всех атрибутов маршрутов и может быть отключено следующим примером:
[RoutePrefix("api/widgets")]
public class WidgetController : Controller {
// GET /api/widgets/colors
[RouteGet("/colors", UseCors = false)]
public IEnumerable<string> GetWidgets() {
return new[] { "Green widget", "Red widget" };
}
}Замена значений в ответе #
Вы можете явно заменить или удалить значения в действии роутера:
[RoutePrefix("api/widgets")]
public class WidgetController : Controller {
public IEnumerable<string> GetWidgets(HttpRequest request) {
// Удаляет заголовок Access-Control-Allow-Credentials
request.Context.OverrideHeaders.AccessControlAllowCredentials = string.Empty;
// Заменяет заголовок Access-Control-Allow-Origin
request.Context.OverrideHeaders.AccessControlAllowOrigin = "https://contorso.com";
return new[] { "Green widget", "Red widget" };
}
}Preflight‑запросы #
Preflight‑запрос — это запрос метода OPTIONS, который клиент отправляет перед фактическим запросом.
Когда запрос с методом OPTIONS совпадает с путём маршрута, но для OPTIONS явно не настроен маршрут, сервер Sisk отвечает 200 OK и соответствующими CORS‑заголовками, после чего клиент может выполнить фактический запрос.
- Если маршрут явно сопоставлен с RouteMethod.Options, например с помощью
MapOptions, этот маршрут обрабатывает запрос вместо автоматического ответа. - Если у маршрута, совпадающего с путём, установлено
UseCors = false, автоматический ответ всё равно отправляется, но без CORS‑заголовков.
Примечание
До версии Sisk 1.7 автоматический ответ на preflight‑запрос всегда включал CORS‑заголовки, даже для маршрутов с UseCors = false.
Отключение CORS глобально #
Это невозможно. Чтобы не использовать CORS, просто не настраивайте его.