Cómo habilitar CORS en ASP.net Core WebAPI

190

Lo que estoy tratando de hacer

Tengo una API web ASP.Net Core de back-end alojada en un plan gratuito de Azure (código fuente: https://github.com/killerrin/Portfolio-Backend ).

También tengo un sitio web de cliente que quiero hacer que consuma esa API. La aplicación de cliente no se alojará en Azure, sino que se alojará en páginas de Github u otro servicio de alojamiento web al que tenga acceso. Debido a esto, los nombres de dominio no se alinearán.

Al investigar esto, necesito habilitar CORS en el lado de la API web, sin embargo, he intentado casi todo durante varias horas y se niega a funcionar.

Cómo tengo la configuración del cliente Es solo un cliente simple escrito en React.js. Estoy llamando a las API a través de AJAX en Jquery. El sitio React funciona, así que sé que no es eso. La llamada a la API de Jquery funciona como lo confirmé en el intento 1. Así es como hago las llamadas

    var apiUrl = "http://andrewgodfroyportfolioapi.azurewebsites.net/api/Authentication";
    //alert(username + "|" + password + "|" + apiUrl);
    $.ajax({
        url: apiUrl,
        type: "POST",
        data: {
            username: username,
            password: password
        },
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        success: function (response) {
            var authenticatedUser = JSON.parse(response);
            //alert("Data Loaded: " + authenticatedUser);
            if (onComplete != null) {
                onComplete(authenticatedUser);
            }
        },
        error: function (xhr, status, error) {
            //alert(xhr.responseText);
            if (onComplete != null) {
                onComplete(xhr.responseText);
            }
        }
    });

Lo que he intentado


Intento 1 - La forma 'adecuada'

https://docs.microsoft.com/en-us/aspnet/core/security/cors

He seguido este tutorial en el sitio web de Microsoft hasta una T, probando las 3 opciones de habilitarlo globalmente en Startup.cs, configurándolo en cada controlador y probándolo en cada acción.

Siguiendo este método, Cross Domain funciona, pero solo en una sola Acción en un solo controlador (POST al AccountController). Para todo lo demás, el Microsoft.AspNetCore.Corsmiddleware se niega a configurar los encabezados.

Instalé a Microsoft.AspNetCore.Corstravés de NUGET y la versión es1.1.2

Así es como lo configuro en Startup.cs

    // This method gets called by the runtime. Use this method to add services to the container.
    public void ConfigureServices(IServiceCollection services)
    {
        // Add Cors
        services.AddCors(o => o.AddPolicy("MyPolicy", builder =>
        {
            builder.AllowAnyOrigin()
                   .AllowAnyMethod()
                   .AllowAnyHeader();
        }));

        // Add framework services.
        services.AddMvc();
        services.Configure<MvcOptions>(options =>
        {
            options.Filters.Add(new CorsAuthorizationFilterFactory("MyPolicy"));
        });

        ...
        ...
        ...
    }

    // This method gets called by the runtime. Use this method to configure 
    //the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IHostingEnvironment env,
    ILoggerFactory loggerFactory)
    {
        loggerFactory.AddConsole(Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        // Enable Cors
        app.UseCors("MyPolicy");

        //app.UseMvcWithDefaultRoute();
        app.UseMvc();

        ...
        ...
        ...
    }

Como puede ver, estoy haciendo todo lo que me dijeron. Agregué Cors antes de MVC las dos veces, y cuando eso no funcionó, intenté poner [EnableCors("MyPolicy")]cada controlador como tal

[Route("api/[controller]")]
[EnableCors("MyPolicy")]
public class AdminController : Controller

Intento 2 - Brute forzándolo

https://andrewlock.net/adding-default-security-headers-in-asp-net-core/

Después de varias horas de intentar el intento anterior, pensé que trataría de aplicar una fuerza bruta al tratar de configurar los encabezados manualmente, obligándolos a ejecutarse en cada respuesta. Hice esto siguiendo este tutorial sobre cómo agregar encabezados manualmente a cada respuesta.

Estos son los encabezados que agregué

.AddCustomHeader("Access-Control-Allow-Origin", "*")
.AddCustomHeader("Access-Control-Allow-Methods", "*")
.AddCustomHeader("Access-Control-Allow-Headers", "*")
.AddCustomHeader("Access-Control-Max-Age", "86400")

Estos son otros encabezados que probé que fallaron

.AddCustomHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH, DELETE")
.AddCustomHeader("Access-Control-Allow-Headers", "content-type, accept, X-PINGOTHER")
.AddCustomHeader("Access-Control-Allow-Headers", "X-PINGOTHER, Host, User-Agent, Accept, Accept: application/json, application/json, Accept-Language, Accept-Encoding, Access-Control-Request-Method, Access-Control-Request-Headers, Origin, Connection, Content-Type, Content-Type: application/json, Authorization, Connection, Origin, Referer")

Con este método, los encabezados Cross Site se aplican correctamente y se muestran en mi consola de desarrollador y en Postman. Sin embargo, el problema es que mientras pasa el Access-Control-Allow-Origincheque, el navegador web lanza un ataque siseante (creo) Access-Control-Allow-Headersindicando415 (Unsupported Media Type)

Entonces el método de fuerza bruta tampoco funciona


Finalmente

¿Alguien ha conseguido que esto funcione y pueda echar una mano, o simplemente poder señalarme en la dirección correcta?


EDITAR

Entonces, para que las llamadas a la API se procesen, tuve que dejar de usar JQuery y cambiar a un XMLHttpRequestformato Javascript puro .

Intento 1

Me las arreglé para Microsoft.AspNetCore.Corsque funcionara siguiendo la respuesta de MindingData, excepto dentro del ConfigureMétodo que pone el app.UseCorsantes app.UseMvc.

Además, cuando se combina con la Solución API de Javascript options.AllowAnyOrigin()para el soporte comodín, comenzó a funcionar también.

Intento 2

Así que he logrado que el Intento 2 (fuerza bruta) funcione ... con la única excepción de que el comodín Access-Control-Allow-Originno funciona y, como tal, tengo que configurar manualmente los dominios que tienen acceso a él.

Obviamente no es ideal, ya que solo quiero que este WebAPI esté abierto para todos, pero al menos funciona para mí en un sitio separado, lo que significa que es un comienzo

app.UseSecurityHeadersMiddleware(new SecurityHeadersBuilder()
    .AddDefaultSecurePolicy()
    .AddCustomHeader("Access-Control-Allow-Origin", "http://localhost:3000")
    .AddCustomHeader("Access-Control-Allow-Methods", "OPTIONS, GET, POST, PUT, PATCH, DELETE")
    .AddCustomHeader("Access-Control-Allow-Headers", "X-PINGOTHER, Content-Type, Authorization"));
Killerrin
fuente
2
Para su 415 (Unsupported Media Type)problema, establezca un Content-Typeencabezado de solicitud en application/json.
Technetium
55
Gracias por dedicar tiempo a escribir una pregunta tan descriptiva.
user1007074
1
Si está probando con Postman, asegúrese de establecer Origin en * o algo para el encabezado de la solicitud, entonces el Intento # 1 debería funcionar. Sin este encabezado, Access-Control-Allow-Origin no se devolverá en el encabezado de respuesta.
tala9999

Respuestas:

240

Debido a que tiene una política CORS muy simple (Permitir todas las solicitudes del dominio XXX), no necesita hacerla tan complicada. Intente hacer lo siguiente primero (Una implementación muy básica de CORS).

Si aún no lo ha hecho, instale el paquete nuget CORS.

Install-Package Microsoft.AspNetCore.Cors

En el método ConfigureServices de su startup.cs, agregue los servicios CORS.

public void ConfigureServices(IServiceCollection services)
{
    services.AddCors(); // Make sure you call this previous to AddMvc
    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}

Luego, en el método Configure de su startup.cs, agregue lo siguiente:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    // Make sure you call this before calling app.UseMvc()
    app.UseCors(
        options => options.WithOrigins("http://example.com").AllowAnyMethod()
    );

    app.UseMvc();
}

Ahora inténtalo. Las políticas son para cuando desea diferentes políticas para diferentes acciones (por ejemplo, diferentes hosts o diferentes encabezados). Por su simple ejemplo, realmente no lo necesita. Comience con este sencillo ejemplo y modifique como lo necesite desde allí.

Leer más: http://dotnetcoretutorials.com/2017/01/03/enabling-cors-asp-net-core/

MindingData
fuente
3
XMLHttpRequest no puede cargar andrewgodfroyportfolioapi.azurewebsites.net/api/Authentication . La respuesta a la solicitud de verificación previa no pasa la verificación de control de acceso: no hay encabezado 'Access-Control-Allow-Origin' en el recurso solicitado. Por lo tanto, el origen ' localhost: 3000 ' no tiene acceso permitido. La respuesta tenía el código de estado HTTP 415.
killerrin
77
Es poco probable que esto funcione, cuando se registre app.UseCors DESPUÉS de `` app.UseMvc () `. Los middlewares se ejecutan en el orden en que están registrados
Tseng,
24
usando app.UseCors antes de app.UseMvc, en el método Configure parece funcionar. Por alguna razón, la secuencia parece importar.
MrClan
1
Para mí, el mayor problema de CORS en 2.0 es que no dice qué está mal, simplemente no puede configurar los encabezados de CORS en silencio. Nota : recuerde agregar todos los encabezados necesarios a la política o fallará (tenía contenido tipo). También es extraño para mí que el middleware CORS no interrumpa el procesamiento de solicitudes, simplemente informando en los registros que el origen no está permitido y ... Pasa la solicitud más (el orden del middleware era correcto).
Andrii M4n0w4R
2
Tuve que habilitar options.DisableHttpsRequirement();para que todo esto funcione. Parece que con la configuración de https cors no se aplicaba.
Michael Brown
210
  • En ConfigureServices agregue services.AddCors(); ANTES de services.AddMvc ();

  • Agregar UseCors en Configurar

     app.UseCors(builder => builder
         .AllowAnyOrigin()
         .AllowAnyMethod()
         .AllowAnyHeader());   
     app.UseMvc();

El punto principal es que agregue app.UseCors, antes app.UseMvc().

Asegúrese de declarar la funcionalidad CORS antes de MVC para que el middleware se active antes de que la tubería MVC obtenga el control y finalice la solicitud.

Después de que el método anterior funcione, puede cambiarlo, configurar un ORIGEN específico para aceptar llamadas api y evitar dejar su API tan abierta a cualquiera

public void ConfigureServices(IServiceCollection services)
{
    services.AddCors(options => options.AddPolicy("ApiCorsPolicy", builder =>
    {
        builder.WithOrigins("http://localhost:4200").AllowAnyMethod().AllowAnyHeader();
    }));

    services.AddMvc();
}

En el método de configuración, dígale a CORS que use la política que acaba de crear:

app.UseCors("ApiCorsPolicy");
app.UseMvc();

Acabo de encontrar este artículo compacto sobre el tema: https://dzone.com/articles/cors-in-net-core-net-core-security-part-vi

Ji Ra
fuente
1
Esto funciona para mi. codeproject.com/Articles/1150023/…
hubert17
17
Esto realmente debería obtener más votos a favor como un buen punto de "inicio". En mi experiencia de más de 25 años de codificación, siempre es bueno saber cómo abrir las compuertas para asegurarse de que realmente "funcione" y luego cerrar / asegurar las cosas según sea necesario.
Indy-Jones
44
Solo por mencionar esto, en contraste con Configure()el orden no es realmente importante aquí dentroConfigureServices()
B12Toaster
Utilicé el enlace en el lector adicional y esos pasos resolvieron este error. No estaba seguro de dónde deberían colocarse estos cambios (pensé que la API). El enlace confirmó que deberían colocarse en la API. Gracias por la ayuda. Estaba totalmente girando mis ruedas con este error.
Richard
1
FYI: la especificación CORS también establece que establecer orígenes en "*" (todos los orígenes) no es válido si el encabezado Access-Control-Allow-Credentials está presente. Lo que significa que no se puede usar AllowCredentials()con lo AllowAnyOrigin()anterior. Para usarlo AllowCredentials()necesitas configurarlo WithOrigins(). docs.microsoft.com/en-us/aspnet/core/security/…
Nick De Beer
28

Creé mi propia clase de middleware que funcionó para mí, creo que hay algo mal con la clase de middleware .net core

public class CorsMiddleware
{
    private readonly RequestDelegate _next;

    public CorsMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public Task Invoke(HttpContext httpContext)
    {
        httpContext.Response.Headers.Add("Access-Control-Allow-Origin", "*");
        httpContext.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
        httpContext.Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type, X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name");
        httpContext.Response.Headers.Add("Access-Control-Allow-Methods", "POST,GET,PUT,PATCH,DELETE,OPTIONS");
        return _next(httpContext);
    }
}

// Extension method used to add the middleware to the HTTP request pipeline.
public static class CorsMiddlewareExtensions
{
    public static IApplicationBuilder UseCorsMiddleware(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<CorsMiddleware>();
    }
}

y lo usé de esta manera en el startup.cs

app.UseCorsMiddleware();
usuario8266077
fuente
Manera muy elegante de ejecutar Access-Control-Allow-Origin.
Artur Poniedziałek
Esto funciona en WebAPI y MVC y no tiene dependencias, ¡Gracias!
Joe
También era escéptico sobre esto, pero funcionó para mí. Intenté básicamente cualquier otro método para lograr esto que pude encontrar en Internet, pero no importa lo que el servidor no responda con los encabezados de acceso. Esto funcionó muy bien. Estoy ejecutando aspnetcore 2.1.
Jordan
Debe devolver los encabezados de cors solo si el cliente envía el encabezado "Origin" en la solicitud. En CospMiddleware original se ve así:if (!context.Request.Headers.ContainsKey(CorsConstants.Origin)) return this._next(context);
Andrew Prigorshnev
2
Tal vez "algo está mal con la clase de middleware de .net core" porque simplemente no agrega el encabezado "Origin" cuando lo prueba con curl o algo así. Los navegadores agregan este encabezado automáticamente cuando realiza una solicitud en código js.
Andrew Prigorshnev
18

En mi caso, solo la getsolicitud funciona bien de acuerdo con la respuesta de MindingData. Para otros tipos de solicitud, debe escribir:

app.UseCors(corsPolicyBuilder =>
   corsPolicyBuilder.WithOrigins("http://localhost:3000")
  .AllowAnyMethod()
  .AllowAnyHeader()
);

No olvides agregar .AllowAnyHeader()

Towhid
fuente
De acuerdo con Towhid en que se necesita AllowAnyHeader (). Dejó que el servidor reciba la solicitud de OPCIONES si a la solicitud de HEADER le falta algo.
Rivon
El .AllowAnyHeader () lo hizo por mí, tuve problemas con la respuesta de verificación previa.
takaz
11

Para ampliar la respuesta del usuario 8266077 , descubrí que aún necesitaba proporcionar la respuesta OPTIONS para las solicitudes de verificación previa en .NET Core 2.1-preview para mi caso de uso:

// https://stackoverflow.com/a/45844400
public class CorsMiddleware
{
  private readonly RequestDelegate _next;

  public CorsMiddleware(RequestDelegate next)
  {
    _next = next;
  }

  public async Task Invoke(HttpContext context)
  {
    context.Response.Headers.Add("Access-Control-Allow-Origin", "*");
    context.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
    // Added "Accept-Encoding" to this list
    context.Response.Headers.Add("Access-Control-Allow-Headers", "Content-Type, X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Accept-Encoding, Content-Length, Content-MD5, Date, X-Api-Version, X-File-Name");
    context.Response.Headers.Add("Access-Control-Allow-Methods", "POST,GET,PUT,PATCH,DELETE,OPTIONS");
    // New Code Starts here
    if (context.Request.Method == "OPTIONS")
    {
      context.Response.StatusCode = (int)HttpStatusCode.OK;
      await context.Response.WriteAsync(string.Empty);
    }
    // New Code Ends here

    await _next(context);
  }
}

y luego habilitó el middleware como en Startup.cs

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
  app.UseMiddleware(typeof(CorsMiddleware));
  // ... other middleware inclusion such as ErrorHandling, Caching, etc
  app.UseMvc();
}
ckr
fuente
1
Recomiendo agregar middleware de esa manera:app.Use<CorsMiddleware>();
Albert221
Puede reemplazar esos 2 líneas: context.Response.StatusCode = (int) HttpStatusCode.OK; esperar contexto.Response.WriteAsync (string.Empty); con un simple: retorno;
Hayha
1
Para ampliar su expansión de la respuesta de @ user8266077: Tenga en cuenta que si la solicitud por algún otro motivo falla, este middleware generará una excepción y los encabezados no se establecerán. Lo que significa que en frontend, todavía se verá como un problema de CORS a pesar de que es algo totalmente diferente. Omití esto al detectar cualquier excepción await _next(context)y configurar el código de estado y la respuesta manualmente si esto sucede. También tuve que agregar "autorización" a Access-Control-Allow-Headers para que la solicitud de verificación previa funcione al hacer solicitudes de reacción que requieren autorización.
Adam
11
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {      
       app.UseCors(builder => builder
                .AllowAnyHeader()
                .AllowAnyMethod()
                .SetIsOriginAllowed((host) => true)
                .AllowCredentials()
            );
    }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors();
    }
Mo D Genesis
fuente
.SetIsOriginAllowed ((host) => true) lo resolvió por mí.
JensB
wow, así que esperaba que cualquiera de las otras respuestas funcionara antes de esta pequeña con solo 3 votos. pero probé meticulosamente cada uno, ... por capricho fui por el tuyo y funcionó. gracias
roberto tomás
Este es el que funcionó para mí en .NET Core 3.1 para permitir casi cualquier cosa.
JustinHui
10

Estuve luchando con esto por DÍAS.

Finalmente lo puse a trabajar al pasar app.UseCors(CORS_POLICY);a la parte superior de Configure().

https://weblog.west-wind.com/posts/2016/sep/26/aspnet-core-and-cors-gotchas

Asegúrese de declarar la funcionalidad CORS antes de> MVC ya que los encabezados deben aplicarse antes de que MVC complete la solicitud.

<= A pesar de que mi aplicación no me llamó UseMVC(), pasar UseCors()al principio solucionó el problema

También:

  • Microsoft.AspNetCore.Corssolía ser un paquete NuGet requerido en .Net Core 2 y versiones inferiores; ahora es automáticamente una parte de Microsoft.AspNetCore en .Net Core 3 y superior.
  • builder.AllowAnyOrigin()y las .AllowCredentials()opciones CORS ahora son mutuamente exclusivas en .Net Core 3 y superior
  • La política de CORS parece requerir que Angular llame al servidor https. Una URL http parecía dar un error CORS independientemente de la configuración CORS del servidor .Net Core. Por ejemplo, http://localhost:52774/api/Contactsdaría un error CORS; simplemente cambiando la URL a https://localhost:44333/api/Contactstrabajado.

Nota adicional :

En mi caso, CORS no funcionaría hasta que me mudé app.UseCors()arriba app.UseEndpoints(endpoints => endpoints.MapControllers()).

Día nubloso
fuente
2
Esta debería ser la respuesta si está utilizando Net Core 3. ¡Gracias por salvarme la vida!
Canadá Wan
2
"Con el enrutamiento de punto final, el middleware CORS debe configurarse para ejecutarse entre las llamadas a UseRouting y UseEndpoints. Una configuración incorrecta hará que el middleware deje de funcionar correctamente". aquí docs.microsoft.com/en-us/aspnet/core/security/…
Mark Schultheiss
"Con el enrutamiento de punto final, el middleware CORS debe configurarse para ejecutarse entre las llamadas a UseRouting y UseEndpoints. Una configuración incorrecta hará que el middleware deje de funcionar correctamente". aquí docs.microsoft.com/en-us/aspnet/core/security/…
Mark Schultheiss
7

Ninguno de los procedimientos anteriores ayudó y luego leí el artículo que resolvió el problema.

Debajo está el código.

public void ConfigureServices(IServiceCollection services)
{
    // Add service and create Policy with options
    services.AddCors(options =>
    {
        options.AddPolicy("CorsPolicy",
            builder => builder.AllowAnyOrigin()
            .AllowAnyMethod()
            .AllowAnyHeader()
            .AllowCredentials() );
    });


    services.AddMvc(); 
}

y

public void Configure(IApplicationBuilder app)
{
    // ...

    // global policy - assign here or on each controller
    app.UseCors("CorsPolicy");

y en la parte superior de mi método de acción

[EnableCors("CorsPolicy")]
Sainath
fuente
2
Probablemente sea una mala idea: no debes mezclar middleware ( app.UseCors()) con [EnableCors()]la misma aplicación. Debería utilizar uno u otro, pero no ambos: docs.microsoft.com/en-us/aspnet/core/security/… :Use the [EnableCors] attribute or middleware, not both in the same app.
FoggyDay
4

intente agregar jQuery.support.cors = true;antes de la llamada Ajax

También podría ser que los datos que envía a la API son inestables,

intente agregar la siguiente función JSON

        var JSON = JSON || {};

    // implement JSON.stringify serialization
    JSON.stringify = JSON.stringify || function (obj) {

        var t = typeof (obj);
        if (t != "object" || obj === null) {

            // simple data type
            if (t == "string") obj = '"' + obj + '"';
            return String(obj);

        }
        else {

            // recurse array or object
            var n, v, json = [], arr = (obj && obj.constructor == Array);

            for (n in obj) {
                v = obj[n]; t = typeof (v);

                if (t == "string") v = '"' + v + '"';
                else if (t == "object" && v !== null) v = JSON.stringify(v);

                json.push((arr ? "" : '"' + n + '":') + String(v));
            }

            return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}");
        }
    };

    // implement JSON.parse de-serialization
    JSON.parse = JSON.parse || function (str) {
        if (str === "") str = '""';
        eval("var p=" + str + ";");
        return p;
    };

luego en sus datos: objeto cambiarlo a

    data: JSON.stringify({
        username: username,
        password: password
    }),
Riaan Saayman
fuente
Gracias por tu ayuda. Definitivamente utilicé una parte de la respuesta para descubrir la solución al final después de combinar las respuestas de todos
killerrin
4

La solución más simple es agregar

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseHsts();
        }

        app.UseCors(options => options.AllowAnyOrigin());

        app.UseHttpsRedirection();
        app.UseMvc();
    }

a Startup.cs.

amilamad
fuente
3

Creo que si usa su propio middleware CORS , debe asegurarse de que realmente sea una solicitud CORS marcando el encabezado de origen .

 public class CorsMiddleware
{
    private readonly RequestDelegate _next;
    private readonly IMemoryCache _cache;
    private readonly ILogger<CorsMiddleware> _logger;

    public CorsMiddleware(RequestDelegate next, IMemoryCache cache, ILogger<CorsMiddleware> logger)
    {
        _next = next;
        _cache = cache;
        _logger = logger;
    }
    public async Task InvokeAsync(HttpContext context, IAdministrationApi adminApi)
    {
        if (context.Request.Headers.ContainsKey(CorsConstants.Origin) || context.Request.Headers.ContainsKey("origin"))
        {
            if (!context.Request.Headers.TryGetValue(CorsConstants.Origin, out var origin))
            {
                context.Request.Headers.TryGetValue("origin", out origin);
            }

            bool isAllowed;
            // Getting origin from DB to check with one from request and save it in cache 
            var result = _cache.GetOrCreateAsync(origin, async cacheEntry => await adminApi.DoesExistAsync(origin));
            isAllowed = result.Result.Result;

            if (isAllowed)
            {
                context.Response.Headers.Add(CorsConstants.AccessControlAllowOrigin, origin);
                context.Response.Headers.Add(
                    CorsConstants.AccessControlAllowHeaders,
                    $"{HeaderNames.Authorization}, {HeaderNames.ContentType}, {HeaderNames.AcceptLanguage}, {HeaderNames.Accept}");
                context.Response.Headers.Add(CorsConstants.AccessControlAllowMethods, "POST, GET, PUT, PATCH, DELETE, OPTIONS");

                if (context.Request.Method == "OPTIONS")
                {
                    _logger.LogInformation("CORS with origin {Origin} was handled successfully", origin);
                    context.Response.StatusCode = (int)HttpStatusCode.NoContent;
                    return;
                }

                await _next(context);
            }
            else
            {
                if (context.Request.Method == "OPTIONS")
                {
                    _logger.LogInformation("Preflight CORS request with origin {Origin} was declined", origin);
                    context.Response.StatusCode = (int)HttpStatusCode.NoContent;
                    return;
                }

                _logger.LogInformation("Simple CORS request with origin {Origin} was declined", origin);
                context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
                return;
            }
        }

        await _next(context);
    }
Riddik
fuente
Muchas gracias. Casi me vuelvo loco, preguntándome por qué Access-Control-Allow-Originel servidor no emitió el encabezado. En realidad, envié solicitudes a través del cartero sin el Originencabezado. Esto me salvó el día! (O al menos mi mañana;))
Paul Kertscher
2

Según su comentario en la respuesta de MindingData, no tiene nada que ver con su CORS, está funcionando bien.

Su acción de controlador está devolviendo los datos incorrectos. HttpCode 415 significa "Tipo de medio no compatible". Esto sucede cuando pasa el formato incorrecto al controlador (es decir, XML a un controlador que solo acepta json) o cuando devuelve un tipo incorrecto (devuelve Xml en un controlador que se declara que solo devuelve xml).

Para más adelante, verifique la existencia del [Produces("...")]atributo en su acción

Tseng
fuente
Gracias por tu ayuda. Intenté una nueva solución y jugué con el envío de json y funcionó después de que lo encadené y lo puse a trabajar
killerrin
2

Para mí, no tenía nada que ver con el código que estaba usando. Para Azure tuvimos que ir a la configuración del Servicio de aplicaciones, en el menú lateral, la entrada "CORS". Allí tuve que agregar el dominio del que estaba solicitando cosas. Una vez que tuve eso, todo fue mágico.

kjbetz
fuente
2

En launchSettings.json, en iisSettings, establezca anonymousAuthentication en true:

"iisSettings": {
    "windowsAuthentication": true,
    "anonymousAuthentication": true,
    "iisExpress": {
      "applicationUrl": "http://localhost:4200/",
      "sslPort": 0
    }
  }

Luego, en Startup.cs, en ConfigureServices, antes de services.AddMvc, agregue:

services.AddCors(options => options.AddPolicy("ApiCorsPolicy", builder =>
{
    builder
        .AllowAnyOrigin()
        .WithHeaders(HeaderNames.AccessControlAllowHeaders, "Content-Type")
        .AllowAnyMethod()
        .AllowCredentials();
}));

y luego, en el método de configuración, antes de app.UseMvc () agregue:

app.UseCors("ApiCorsPolicy");
Adrian
fuente
Esto lo hizo por mí, originalmente configuré mi proyecto para la autenticación de Windows, pero luego tuve que cambiarlo a anónimo, tenía CORS configurado correctamente pero esta configuración en launchSettings.json fue el culpable, ¡gracias por publicar esto!
HaRoLD
2

Estoy usando .Net CORE 3.1 y pasé años golpeándome la cabeza contra la pared con este cuando me di cuenta de que mi código realmente comenzó a funcionar pero mi entorno de depuración estaba roto, así que aquí hay 2 pistas si está tratando de solucionar el problema. problema:

  1. Si está intentando registrar encabezados de respuesta utilizando el middleware ASP.NET, el encabezado "Access-Control-Allow-Origin" nunca aparecerá, incluso si está allí. No sé cómo, pero parece que se agregó fuera de la tubería (al final tuve que usar wireshark para verlo).

  2. .NET CORE no enviará el "Acceso-Control-Permitir-Origen" en la respuesta a menos que tenga un encabezado "Origen" en su solicitud. El cartero no configurará esto automáticamente, por lo que deberá agregarlo usted mismo.

Andy
fuente
2

En mi caso lo arreglé con UseCors antes de UserRouting ..

René Bizelli de Oliveira
fuente
Me encontré con algo similar cuando actualicé de dotnet core 2.2 a 3.1. Tuve que mover app.UseCors () sobre app.UseRouting (). Esta respuesta me señaló en la dirección correcta.
Brandonm
1

.NET Core 3.1

Funcionó para mí y cómo dicen los documentos para hacerlo:

en la clase de inicio:

readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins"; 

En el método ConfigureServices ():

    services.AddCors(options =>
    {
        options.AddPolicy(MyAllowSpecificOrigins,
        builder =>
        {
            builder.WithOrigins("http://example.com",
                                "http://www.contoso.com");
        });
    });

En el método Configure ():

    app.UseCors(MyAllowSpecificOrigins);  

https://docs.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-3.1

Andrés
fuente
0

Obtuve la respuesta anterior de MindingData para trabajar, pero tuve que usar Microsoft.AspNet.Cors en lugar de Microsoft.AspNetCore.Cors. Estoy usando el proyecto de API de aplicación web .NetCore en Visual Studio 2019

carl
fuente
2
NOTA: no debe usar Microsoft.AspNet.Cors en una aplicación ASP.Net Cor. Si tiene .Net Core 3.0 o superior, no necesita importar ningún paquete NuGet para CORS. Si está utilizando .Net Core 2.3 o inferior, entonces necesita la versión adecuada de Microsoft.AspNet.Cors de NuGet.
FoggyDay
0

los

Microsoft.AspNetCore.Cors

le permitirá hacer CORS con funciones integradas, pero no maneja la solicitud de OPCIONES. La mejor solución hasta ahora es crear un nuevo Middleware como se sugirió en una publicación anterior. Marque la respuesta marcada como correcta en la siguiente publicación:

Habilite el encabezado OPTIONS para CORS en .NET Core Web API

Bonomi
fuente
0

Forma simple y fácil de hacerlo.

  1. Paquete de instalación

Install-Package Microsoft.AspNetCore.Cors

  1. Ponga esto debajo del código en el archivo startup.cs

app.UseCors(options => options.AllowAnyOrigin());

pintu sharma
fuente
0

Aquí está mi código :)

  app.Use((ctx, next) =>
        {
            ctx.Response.Headers.Add("Access-Control-Allow-Origin", ctx.Request.Headers["Origin"]);
            ctx.Response.Headers.Add("Access-Control-Allow-Methods", "*");
            ctx.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
            ctx.Response.Headers.Add("Access-Control-Allow-Headers", "AccessToken,Content-Type");
            ctx.Response.Headers.Add("Access-Control-Expose-Headers", "*");
            if (ctx.Request.Method.ToLower() == "options")
            {
                ctx.Response.StatusCode = 204;

                return Task.CompletedTask;
            }
            return next();
        });
Lnn
fuente
0

Así es como hice esto.

Veo que en algunas respuestas están configurando app.UserCors("xxxPloicy")y poniendo [EnableCors("xxxPloicy")]controladores. No necesitas hacer las dos cosas.

Aquí están los pasos.

En Startup.cs dentro de ConfigureServices agregue el siguiente código.

    services.AddCors(c=>c.AddPolicy("xxxPolicy",builder => {
        builder.AllowAnyOrigin()
        .AllowAnyMethod()
        .AllowAnyHeader();
    }));

Si desea aplicar en todo el proyecto, agregue el siguiente código en el método Configurar en Startup.cs

app.UseCors("xxxPolicy");

O

Si desea agregarlo a los controladores específicos, agregue el código de habilitación de cors como se muestra a continuación.

[EnableCors("xxxPolicy")]
[Route("api/[controller]")]
[ApiController]
public class TutorialController : ControllerBase {}

Para más información: ver esto

Arshath Shameer
fuente
0

Use un atributo de acción / controlador personalizado para configurar los encabezados CORS.

Ejemplo:

public class AllowMyRequestsAttribute : ControllerAttribute, IActionFilter
{
    public void OnActionExecuted(ActionExecutedContext context)
    {
        // check origin
        var origin = context.HttpContext.Request.Headers["origin"].FirstOrDefault();
        if (origin == someValidOrigin)
        {
            context.HttpContext.Response.Headers.Add("Access-Control-Allow-Origin", origin);
            context.HttpContext.Response.Headers.Add("Access-Control-Allow-Credentials", "true");
            context.HttpContext.Response.Headers.Add("Access-Control-Allow-Headers", "*");
            context.HttpContext.Response.Headers.Add("Access-Control-Allow-Methods", "*");
            // Add whatever CORS Headers you need.
        }
    }

    public void OnActionExecuting(ActionExecutingContext context)
    {
        // empty
    }
}

Luego, en el controlador / acción de la API web:

[ApiController]
[AllowMyRequests]
public class MyController : ApiController
{
    [HttpGet]
    public ActionResult<string> Get()
    {
        return "Hello World";
    }
}
warrickh
fuente
0

Solo para agregar una respuesta aquí, si está utilizando app.UseHttpsRedirection()y no está utilizando el puerto SSL, considere comentar esto.

Raj
fuente
0

Estaba usando blazor webassembly como cliente y asp.net web api core como backend y también tuve un problema de cors.

Encontré solución con este código:

Mi ASP.Net core web api Startup.cs ConfigureServices y Configure primera línea de métodos se ve así:

public void ConfigureServices(IServiceCollection services)
{
   services.AddCors(options => options.AddPolicy("ApiCorsPolicy", builder =>
   {
        builder.WithOrigins("http://example.com").AllowAnyMethod().AllowAnyHeader();
    }));

 //other code below...
}

y mi método de configuración:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseCors(
        options =>   options.WithOrigins("http://example.com").AllowAnyMethod().AllowAnyHeader()
            );
 //other code below...
}

cambiar http://example.comcon su dominio de cliente o dirección IP

Zviadi
fuente
-1
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
                .AddJsonOptions(options => {
                    var resolver = options.SerializerSettings.ContractResolver;
                    if (resolver != null)
                        (resolver as DefaultContractResolver).NamingStrategy = null;
                });

            services.AddDbContext<PaymentDetailContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DevConnection"))); //Dependency Injection
            // options => options.UseSqlServer() Lamda Expression

            services.AddCors(options =>
            {
                options.AddPolicy(MyAllowSpecificOrigins,
                    builder =>
                    {
                        builder.WithOrigins("http://localhost:4200").AllowAnyHeader()
                                .AllowAnyMethod(); ;
                    });
            });
Albin CS
fuente
Edite su respuesta para incluir y explicar su código y cómo difiere de las otras respuestas. Esto hará que su publicación sea más útil y más probable para que sea votada :)
Das_Geek