Sisk

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:

HTTP
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
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-Origin es https://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).

HTTP
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:

C#
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
HTTP/1.1 200 OK
Access-Control-Allow-Origin: http://example.com
Access-Control-Allow-Headers: Authorization
Access-Control-Expose-Headers: Content-Type

Estos 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.

C#
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:

C#
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:

C#
[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:

C#
[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.

Escribe para buscar en la documentación y en la referencia de la API.