Habilitando CORS (Compartir Recursos entre Orígenes) en Sisk
Esta página fue traducida automáticamente del inglés. Leer el original
Sisk tiene una herramienta que puede ser útil para manejar Cross-Origin Resource Sharing (CORS) al exponer tu servicio públicamente. Esta característica no forma parte del protocolo HTTP sino que es una característica específica de los navegadores web definida por el W3C. Este mecanismo de seguridad impide que una página web realice peticiones a un dominio diferente al que proporcionó la página web. Un proveedor de servicios puede permitir que ciertos dominios accedan a sus recursos, o solo a uno.
Same Origin #
Para que un recurso se identifique como “misma origen”, una solicitud debe incluir el encabezado Origin en su petición:
GET /api/users HTTP/1.1
Host: example.com
Origin: http://example.com
...Y el servidor remoto debe responder con un encabezado Access-Control-Allow-Origin con el mismo valor que el origen solicitado:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://example.com
...Esta verificación es explícita: el host, puerto y protocolo deben ser los mismos que los solicitados. Revisa el ejemplo:
- Un servidor responde que su
Access-Control-Allow-Origineshttps://example.com:https://example.net- el dominio es diferente.http://example.com- el esquema es diferente.http://example.com:5555- el puerto es diferente.https://www.example.com- el host es diferente.
En la especificación, solo se permite la sintaxis para ambos encabezados, tanto en solicitudes como en respuestas. La ruta de la URL se ignora. El puerto también se omite si es un puerto predeterminado (80 para HTTP y 443 para HTTPS).
Origin: null
Origin: <scheme>://<hostname>
Origin: <scheme>://<hostname>:<port>Enabling CORS #
De forma nativa, dispones del objeto CrossOriginResourceSharingHeaders dentro de tu ListeningHost.
Puedes configurar CORS al inicializar el servidor:
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();
}El código anterior enviará los siguientes encabezados para todas las respuestas:
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://example.com
Access-Control-Allow-Headers: Authorization
Access-Control-Expose-Headers: Content-TypeEstos encabezados deben enviarse para todas las respuestas a un cliente web, incluidos errores y redirecciones.
Puede que notes que la clase CrossOriginResourceSharingHeaders tiene dos propiedades similares: AllowOrigin y AllowOrigins. Ten en cuenta que una es plural y la otra singular.
- La propiedad AllowOrigin es estática: solo el origen que especifiques será enviado para todas las respuestas.
- La propiedad AllowOrigins es dinámica: el servidor verifica si el origen de la solicitud está contenido en esta lista. Si se encuentra, se envía en la respuesta de ese origen.
Cuando el origen permitido depende de la solicitud, es decir, cuando utilizas AllowOrigins o el valor AutoAllowOrigin descrito a continuación, Sisk también envía el encabezado Vary: Origin para que las cachés no reutilicen una respuesta para un origen diferente.
Wildcards and automatic headers #
Alternativamente, puedes usar un comodín (*) en el origen de la respuesta para especificar que cualquier origen está permitido para acceder al recurso. Sin embargo, este valor no está permitido para solicitudes que incluyen credenciales (encabezados de autorización) y esta operación resultará en un error.
Puedes solucionar este problema enumerando explícitamente qué orígenes estarán permitidos mediante la propiedad AllowOrigins o también usar la constante AutoAllowOrigin en el valor de AllowOrigin. Esta propiedad mágica definirá el encabezado Access-Control-Allow-Origin con el mismo valor que el encabezado Origin de la solicitud.
También puedes usar AutoFromRequestMethod y AutoFromRequestHeaders para un comportamiento similar a AllowOrigin, que responde automáticamente según los encabezados enviados.
using var host = HttpServer.CreateBuilder()
.UseCors(new CrossOriginResourceSharingHeaders(
// Responde según el encabezado Origin de la solicitud
allowOrigin: CrossOriginResourceSharingHeaders.AutoAllowOrigin,
// Responde según el encabezado Access-Control-Request-Method o el método de la solicitud
allowMethods: [CrossOriginResourceSharingHeaders.AutoFromRequestMethod],
// Responde según el encabezado Access-Control-Request-Headers o los encabezados enviados
allowHeaders: [CrossOriginResourceSharingHeaders.AutoFromRequestHeaders],
exposeHeaders: [HttpKnownHeaderNames.ContentType, "X-Authenticated-Account-Id"],
allowCredentials: true))
.Build();Other Ways to Apply CORS #
Si estás trabajando con service providers, puedes sobrescribir los valores definidos en el archivo de configuración:
static async Task Main(string[] args)
{
using var app = HttpServer.CreateBuilder()
.UsePortableConfiguration(...)
.UseCors(cors => {
// Sobrescribirá el origen definido en la configuración
// del archivo.
cors.AllowOrigin = "http://example.com";
})
.Build();
await app.StartAsync();
}Disabling CORS on Specific Routes #
La propiedad UseCors está disponible tanto para rutas como para todos los atributos de ruta y puede desactivarse con el siguiente ejemplo:
[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" };
}
}Replacing Values in the Response #
Puedes reemplazar o eliminar valores explícitamente en una acción del router:
[RoutePrefix("api/widgets")]
public class WidgetController : Controller {
public IEnumerable<string> GetWidgets(HttpRequest request) {
// Elimina el encabezado Access-Control-Allow-Credentials
request.Context.OverrideHeaders.AccessControlAllowCredentials = string.Empty;
// Reemplaza el encabezado Access-Control-Allow-Origin
request.Context.OverrideHeaders.AccessControlAllowOrigin = "https://contorso.com";
return new[] { "Green widget", "Red widget" };
}
}Preflight Requests #
Una solicitud de preflight es una petición OPTIONS que el cliente envía antes de la solicitud real.
Cuando una solicitud con el método OPTIONS coincide con la ruta de un endpoint, pero no hay una ruta configurada explícitamente para OPTIONS, el servidor Sisk responde con un 200 OK y los encabezados CORS aplicables, y luego el cliente puede continuar con la solicitud real.
- Si una ruta está mapeada explícitamente con RouteMethod.Options, por ejemplo con
MapOptions, esa ruta maneja la solicitud en lugar de la respuesta automática. - Si la ruta que coincide con la ruta tiene
UseCors = false, la respuesta automática aún se envía, pero sin encabezados CORS.
Nota
Antes de Sisk 1.7, la respuesta automática de preflight siempre incluía los encabezados CORS, incluso para rutas con UseCors = false.
Disabling CORS Globally #
No es posible hacer esto. Para no usar CORS, simplemente no lo configures.