Como habilitar o CORS no ASP.net Core WebAPI

190

O que estou tentando fazer

Eu tenho uma API Web ASP.Net Core de back-end hospedada em um Plano Gratuito do Azure (código-fonte: https://github.com/killerrin/Portfolio-Backend ).

Eu também tenho um site do cliente que eu quero fazer consumir essa API. O Aplicativo Cliente não será hospedado no Azure, mas sim nas Páginas do Github ou em outro Serviço de Hospedagem da Web ao qual tenho acesso. Por esse motivo, os nomes de domínio não se alinham.

Analisando isso, preciso habilitar o CORS no lado da API da Web, no entanto, tentei quase tudo por várias horas e agora ele se recusa a trabalhar.

Como eu tenho a configuração do cliente É apenas um cliente simples escrito em React.js. Estou chamando as APIs através do AJAX no Jquery. O site React funciona, então eu sei que não é isso. A chamada da API do Jquery funciona como eu confirmei na tentativa 1. Aqui está como eu faço as chamadas

    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);
            }
        }
    });

O que eu tentei


Tentativa 1 - O caminho 'adequado'

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

Eu segui este tutorial no site da Microsoft até um T, tentando todas as 3 opções de ativá-lo globalmente no Startup.cs, configurando-o em todos os controladores e testando-o em todas as ações.

Seguindo esse método, o domínio cruzado funciona, mas apenas em uma única ação em um único controlador (POST para o AccountController). Para todo o resto, o Microsoft.AspNetCore.Corsmiddleware se recusa a definir os cabeçalhos.

Eu instalei Microsoft.AspNetCore.Corsatravés do NUGET e a versão é1.1.2

Aqui está como eu o configurei no 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 você pode ver, estou fazendo tudo o que foi dito. Eu adiciono Cors antes do MVC as duas vezes e, quando isso não funcionou, tentei colocar [EnableCors("MyPolicy")]todos os controladores assim

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

Tentativa 2 - Brute Forçando-o

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

Depois de várias horas tentando a tentativa anterior, imaginei que tentaria forçá-la tentando definir os cabeçalhos manualmente, forçando-os a executar todas as respostas. Fiz isso seguindo este tutorial sobre como adicionar cabeçalhos manualmente a todas as respostas.

Estes são os cabeçalhos que adicionei

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

Estes são outros cabeçalhos que tentei que falharam

.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")

Com esse método, os cabeçalhos entre sites estão sendo aplicados corretamente e são exibidos no meu console do desenvolvedor e no Postman. O problema, no entanto, é que, enquanto passa na Access-Control-Allow-Originverificação, o navegador da web lança um chiado (acredito) Access-Control-Allow-Headersafirmando415 (Unsupported Media Type)

Portanto, o método da força bruta também não funciona


Finalmente

Alguém conseguiu que isso funcionasse e poderia dar uma mãozinha ou apenas ser capaz de me apontar na direção certa?


EDITAR

Portanto, para obter as chamadas da API, tive que parar de usar o JQuery e mudar para o XMLHttpRequestformato Javascript puro .

Tentativa 1

Eu consegui fazer o Microsoft.AspNetCore.Corstrabalho seguindo a resposta de MindingData, exceto dentro do Configuremétodo colocando o app.UseCorsantes app.UseMvc.

Além disso, quando combinado com a solução da API Javascript options.AllowAnyOrigin()para suporte a caracteres curinga começou a funcionar também.

Tentativa 2

Então, eu consegui fazer com que a Tentativa 2 (força bruta) funcione ... com a única exceção de que o curinga Access-Control-Allow-Originnão funciona e, como tal, tenho que definir manualmente os domínios que têm acesso a ela.

Obviamente, não é o ideal, pois eu só quero que essa WebAPI seja aberta a todos, mas pelo menos funciona para mim em um site separado, o que significa que é um começo

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
fonte
2
Para o seu 415 (Unsupported Media Type)problema, defina um Content-Typecabeçalho de solicitação como application/json.
Technetium
5
Obrigado por dedicar seu tempo a escrever uma pergunta tão descritiva.
user1007074
1
Se você estiver testando usando o Postman, certifique-se de definir Origem como * ou algo para o cabeçalho da solicitação, e a Tentativa nº 1 deve funcionar. Sem esse cabeçalho, o Access-Control-Allow-Origin não será retornado no cabeçalho de resposta.
tala9999

Respostas:

239

Como você possui uma política CORS muito simples (Permitir todas as solicitações do domínio XXX), não é necessário torná-la tão complicada. Tente fazer o seguinte primeiro (uma implementação muito básica do CORS).

Se você ainda não o fez, instale o pacote de nuget CORS.

Install-Package Microsoft.AspNetCore.Cors

No método ConfigureServices do seu startup.cs, adicione os serviços CORS.

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

Em seguida, no método Configure do seu startup.cs, adicione o seguinte:

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();
}

Agora tente. As políticas são para quando você deseja políticas diferentes para ações diferentes (por exemplo, hosts diferentes ou cabeçalhos diferentes). Para seu exemplo simples, você realmente não precisa dele. Comece com este exemplo simples e ajuste conforme necessário a partir daí.

Outras leituras: http://dotnetcoretutorials.com/2017/01/03/enabling-cors-asp-net-core/

MindingData
fonte
3
XMLHttpRequest não pode carregar andrewgodfroyportfolioapi.azurewebsites.net/api/Authentication . A resposta à solicitação de comprovação não passa na verificação do controle de acesso: Nenhum cabeçalho 'Access-Control-Allow-Origin' está presente no recurso solicitado. Origem ' localhost: 3000 ' não é, portanto, permitido o acesso. A resposta tinha código de status HTTP 415.
killerrin
7
É improvável que isso funcione quando você registra app.UseCors APÓS `` app.UseMvc () `. Middlewares são executados na ordem em que são registrados
Tseng
24
usando app.UseCors antes de app.UseMvc, no método Configure parece funcionar. Por alguma razão, a sequência parece importar.
MrClan
1
Para mim, o maior problema do CORS no 2.0 é que ele não diz o que está errado, apenas falha silenciosamente ao definir os cabeçalhos do CORS. Nota : lembre-se de adicionar todos os cabeçalhos necessários à política ou ela falhará (eu tinha o tipo de conteúdo). Também é estranho para mim que o middleware CORS não freie o processamento de solicitações, apenas informando nos logs que a origem não é permitida e ... Passa a solicitação adicional (a ordem do middleware estava correta).
Andrii M4n0w4R 13/11
2
Eu tive que habilitar para que options.DisableHttpsRequirement();isso funcionasse. Parece que com as configurações https cors não estavam sendo aplicadas.
Michael Brown
210
  • No ConfigureServices, adicione services.AddCors(); ANTES de services.AddMvc ();

  • Adicionar UseCors no Configure

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

O ponto principal é que adicionar app.UseCorsantes app.UseMvc().

Certifique-se de declarar a funcionalidade CORS antes do MVC, para que o middleware seja acionado antes que o pipeline do MVC obtenha o controle e finalize a solicitação.

Depois que o método acima funciona, você pode alterá-lo, configurar uma ORIGIN específica para aceitar chamadas da API e evitar deixar sua API tão aberta para qualquer pessoa

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

    services.AddMvc();
}

No método configure, diga ao CORS para usar a política que você acabou de criar:

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

Acabei de encontrar este artigo compacto sobre o assunto - https://dzone.com/articles/cors-in-net-core-net-core-security-part-vi

Ji Ra
fonte
1
Isso funciona para mim. codeproject.com/Articles/1150023/...
hubert17
17
Isso realmente deve receber mais votos como um bom ponto de partida. Na minha experiência de mais de 25 anos de codificação, é sempre bom saber como abrir as comportas para garantir que realmente funcione e depois feche / proteja as coisas conforme necessário.
Indianapolis-Jones
4
Só para mencionar isso, em contraste com Configure()a ordem não é realmente importante aqui dentroConfigureServices()
B12Toaster
Usei o link no Leitor Adicional e essas etapas resolveram esse erro. Eu não tinha certeza de onde essas alterações deveriam ser colocadas (pensei na API). O link confirmou que eles deveriam ser colocados na API. Obrigado pela ajuda. Eu estava girando totalmente minhas rodas com esse erro.
21418 Richard
1
FYI - A especificação CORS também afirma que definir origens para "*" (todas as origens) é inválido se o cabeçalho Access-Control-Allow-Credentials estiver presente. Ou seja, você não pode usar AllowCredentials()com AllowAnyOrigin()como acima. Para usar, AllowCredentials()você precisa definir WithOrigins(). docs.microsoft.com/en-us/aspnet/core/security/…
Nick De Beer
28

Eu criei minha própria classe de middleware que funcionou para mim, acho que há algo errado com a classe 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>();
    }
}

e usado dessa maneira no startup.cs

app.UseCorsMiddleware();
user8266077
fonte
Maneira muito elegante de executar o Access-Control-Allow-Origin.
Artur Poniedziałek
Isso funciona no WebAPI e MVC e não tem dependências, obrigado!
314 Joe
Também fiquei cético quanto a isso, mas funcionou para mim. Tentei basicamente todos os outros métodos para conseguir isso que consegui encontrar na internet, mas independentemente do que o servidor não respondesse com os cabeçalhos de acesso. Isso funcionou muito bem. Estou executando o aspnetcore 2.1.
19418 Jordan
Você deve retornar cabeçalhos cors apenas se o cliente enviar o cabeçalho "Origem" na solicitação. No CospMiddleware original, ele se parece com o seguinte:if (!context.Request.Headers.ContainsKey(CorsConstants.Origin)) return this._next(context);
Andrew Prigorshnev 27/06/19
2
Talvez "algo de errado com a classe de middleware .net core", porque você simplesmente não adiciona o cabeçalho "Origin" ao testá-lo com curl ou algo assim. Os navegadores adicionam esse cabeçalho automaticamente quando você faz uma solicitação no código js.
Andrew Prigorshnev 27/06/19
18

No meu caso, apenas o getpedido funciona bem de acordo com a resposta do MindingData. Para outros tipos de solicitação, você precisa escrever:

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

Não esqueça de adicionar .AllowAnyHeader()

Towhid
fonte
Concorde com Towhid que AllowAnyHeader () é necessário. Ele permite que o servidor receba a solicitação OPTIONS se houver falta de alguma solicitação na HEADER.
Rivon #
O .AllowAnyHeader () fez isso por mim, tive problemas com a resposta de comprovação.
takaz
11

Para expandir a user8266077 's resposta , eu descobri que eu ainda precisava de resposta opções de fornecimento de pedidos de pré-vôo em .NET Núcleo 2,1-visualização para o meu 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);
  }
}

e, em seguida, habilitou o middleware como em Startup.cs

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
  app.UseMiddleware(typeof(CorsMiddleware));
  // ... other middleware inclusion such as ErrorHandling, Caching, etc
  app.UseMvc();
}
ckr
fonte
1
Eu recomendo adicionar middleware dessa forma:app.Use<CorsMiddleware>();
Albert221
Você pode substituir esses 2 itens: context.Response.StatusCode = (int) HttpStatusCode.OK; aguarde context.Response.WriteAsync (string.Empty); com um simples: retorno;
21718
1
Para expandir sua resposta à resposta de @ user8266077: Lembre-se de que, se a solicitação por algum outro motivo falhar, esse middleware emitirá uma exceção e os cabeçalhos não serão definidos. Isso significa que, no front-end, ainda parecerá um problema do CORS, mesmo que seja algo totalmente diferente. Eu ignorei isso capturando todas as exceções await _next(context)e definindo o código de status e a resposta manualmente, se isso acontecer. Eu também tive que adicionar "autorização" a Access-Control-Allow-Headers para que a solicitação de comprovação funcione ao fazer solicitações de reação que exijam autorização.
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
fonte
.SetIsOriginAllowed ((host) => true) resolveu isso para mim.
JensB 18/01
uau, então eu esperava que qualquer uma das outras respostas funcionasse antes dessa pequena com apenas 3 votos. mas tentei meticulosamente cada um, ... por um capricho, fui pelo seu e funcionou. obrigado
roberto tomás
Essa foi a que funcionou para mim no .NET Core 3.1 para permitir praticamente qualquer coisa.
JustinHui 8/07
10

Eu estava lutando com isso por dias.

Finalmente consegui trabalhar movendo app.UseCors(CORS_POLICY); para o TOPO de Configure().

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

Certifique-se de declarar a funcionalidade CORS antes de> MVC, pois os cabeçalhos devem ser aplicados antes que o MVC conclua a solicitação.

<= Mesmo que meu aplicativo não tenha ligado UseMVC(), movendoUseCors() para o topo corrigiu o problema

Além disso:

  • Microsoft.AspNetCore.Corscostumava ser um pacote NuGet necessário no .Net Core 2 e inferior; agora faz parte automaticamente do Microsoft.AspNetCore no .Net Core 3 e superior.
  • builder.AllowAnyOrigin() e .AllowCredentials() CORS agora são mutuamente exclusivas no .Net Core 3 e superior
  • A política do CORS parece exigir a chamada Angular ao servidor https. Um URL http parecia dar um erro CORS, independentemente da configuração CORS do servidor .Net Core. Por exemplo, http://localhost:52774/api/Contactsdaria um erro de CORS; simplesmente alterando o URL para https://localhost:44333/api/Contactsfuncionado.

Nota adicional :

No meu caso, o CORS não funcionaria até que eu me movesse app.UseCors()acima app.UseEndpoints(endpoints => endpoints.MapControllers()).

FoggyDay
fonte
2
Essa deve ser a resposta se você estiver usando o Net Core 3. Obrigado por salvar minha vida!
Canada Wan
2
"Com o roteamento do nó de extremidade, o middleware CORS deve ser configurado para ser executado entre as chamadas para UseRouting e UseEndpoints. A configuração incorreta fará com que o middleware pare de funcionar corretamente." aqui docs.microsoft.com/en-us/aspnet/core/security/…
Mark Schultheiss
"Com o roteamento do nó de extremidade, o middleware CORS deve ser configurado para ser executado entre as chamadas para UseRouting e UseEndpoints. A configuração incorreta fará com que o middleware pare de funcionar corretamente." aqui docs.microsoft.com/en-us/aspnet/core/security/…
Mark Schultheiss
7

Nenhum dos procedimentos acima ajudou e li o artigo que resolveu o problema.

Abaixo está o 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(); 
}

e

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

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

e no topo do meu método de ação

[EnableCors("CorsPolicy")]
Sainath
fonte
2
Provavelmente, essa é uma péssima idéia: você não deve misturar o middleware ( app.UseCors()) com [EnableCors()]o mesmo aplicativo. Você deve usar um ou outro - mas não os dois: docs.microsoft.com/en-us/aspnet/core/security/… :Use the [EnableCors] attribute or middleware, not both in the same app.
FoggyDay
4

tente adicionar jQuery.support.cors = true; antes da chamada do Ajax

Também pode ser que os dados que você está enviando para a API sejam instáveis,

tente adicionar a seguinte função 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;
    };

em seus dados: objeto, altere-o para

    data: JSON.stringify({
        username: username,
        password: password
    }),
Riaan Saayman
fonte
Obrigado pela ajuda. Definitivamente utilizada uma parte da resposta a figura para fora da solução no fim depois de combinar todos os gostos respostas
killerrin
4

A solução mais simples é adicionar

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

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

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

para Startup.cs.

amilamad
fonte
3

Acho que se você usa seu próprio middleware CORS, precisa se certificar de que é realmente uma solicitação CORS , verificando o cabeçalho de origem .

 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
fonte
Muito obrigado. Eu quase enlouqueci, me perguntando por que o Access-Control-Allow-Origincabeçalho não foi emitido pelo servidor. Na verdade, enviei solicitações via Postman sem o Origincabeçalho. Isso salvou meu dia! (Ou pelo menos a minha manhã;))
Paul Kertscher
2

Com base no seu comentário na resposta do MindingData, isso não tem nada a ver com o seu CORS, está funcionando bem.

Sua ação do controlador está retornando os dados incorretos. HttpCode 415 significa "Tipo de mídia não suportado". Isso acontece quando você passa o formato errado para o controlador (ou seja, XML para um controlador que aceita apenas json) ou quando retorna um tipo errado (retorna Xml em um controlador declarado para retornar apenas xml).

Para mais tarde, verifique a existência do [Produces("...")]atributo em sua ação

Tseng
fonte
Obrigado pela ajuda. Tentou uma nova solução e jogou com JSON sendo enviados para fora e deu certo depois que eu Stringified-lo e tenho que trabalhar
killerrin
2

Para mim, não tinha nada a ver com o código que eu estava usando. Para o Azure, tivemos que entrar nas configurações do Serviço de Aplicativo, no menu lateral, na entrada "CORS". Lá, tive que adicionar o domínio do qual estava solicitando coisas. Depois que eu entendi, tudo foi mágico.

kjbetz
fonte
2

No launchSettings.json, em iisSettings, defina anonymousAuthentication como true:

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

Em Startup.cs, em ConfigureServices, antes de services.AddMvc, adicione:

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

e, em seguida, no método configure, antes de app.UseMvc () adicione:

app.UseCors("ApiCorsPolicy");
Adrian
fonte
Isso foi feito por mim. Inicialmente, configurei meu projeto para autenticação do Windows, mas tive que alterá-lo para anônimo. O CORS foi configurado corretamente, mas essa configuração no launchSettings.json foi a culpada, obrigado por postar isso !.
HaRoLD 26/08/19
2

Estou usando o .Net CORE 3.1 e passei anos batendo minha cabeça contra uma parede com essa quando percebi que meu código estava realmente funcionando, mas meu ambiente de depuração estava quebrado, então aqui estão duas dicas, se você estiver tentando solucionar o problema problema:

  1. Se você estiver tentando registrar cabeçalhos de resposta usando o middleware ASP.NET, o cabeçalho "Access-Control-Allow-Origin" nunca será exibido, mesmo que esteja lá. Não sei como, mas parece ser adicionado fora do pipeline (no final, tive que usar o wireshark para vê-lo).

  2. O .NET CORE não enviará o "Access-Control-Allow-Origin" na resposta, a menos que você tenha um cabeçalho "Origin" em sua solicitação. O Carteiro não definirá isso automaticamente, portanto você precisará adicioná-lo.

Andy
fonte
2

No meu caso, eu consertei com o UseCors antes do UserRouting.

René Bizelli de Oliveira
fonte
Encontrei algo semelhante quando atualizei do dotnet core 2.2 para 3.1. Teve que mover app.UseCors () acima app.UseRouting (). Essa resposta me apontou na direção certa.
Brandonm 13/07
1

.NET Core 3.1

Trabalhou para mim e como os documentos dizem para fazê-lo:

na classe Inicialização:

readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins"; 

No método ConfigureServices ():

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

No método Configure ():

    app.UseCors(MyAllowSpecificOrigins);  

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

Andrew
fonte
0

Eu obtive a resposta do MindingData acima para funcionar, mas tive que usar o Microsoft.AspNet.Cors em vez do Microsoft.AspNetCore.Cors. Estou usando o projeto .NetCore Web Application API no Visual Studio 2019

carl
fonte
2
NOTA: você não deve usar Microsoft.AspNet.Cors em um aplicativo ASP.Net Cor. Se você usa o .Net Core 3.0 ou superior, não precisa importar nenhum pacote NuGet para o CORS. Se você estiver no .Net Core 2.3 ou inferior, precisará da versão apropriada do Microsoft.AspNet.Cors da NuGet.
FoggyDay
0

o

Microsoft.AspNetCore.Cors

permitirá que você execute o CORS com recursos internos, mas ele não processa a solicitação OPTIONS. Até agora, a melhor solução alternativa é criar um novo Middleware, conforme sugerido em uma postagem anterior. Verifique a resposta marcada como correta na seguinte postagem:

Ativar cabeçalho OPTIONS para CORS na API da Web do .NET Core

Bonomi
fonte
0

Maneira simples e fácil de fazê-lo.

  1. Instalar pacote

Install-Package Microsoft.AspNetCore.Cors

  1. Coloque este código abaixo no arquivo startup.cs

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

pintu sharma
fonte
0

Aqui está o meu 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
fonte
0

Aqui está como eu fiz isso.

Vejo que em algumas respostas eles estão definindo app.UserCors("xxxPloicy")e colocando[EnableCors("xxxPloicy")] controladores. Você não precisa fazer as duas coisas.

Aqui estão os passos.

Em Startup.cs, no ConfigureServices, adicione o seguinte código.

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

Se você deseja aplicar todo o projeto, adicione o seguinte código no método Configure em Startup.cs

app.UseCors("xxxPolicy");

Ou

Se você deseja adicioná-lo aos controladores específicos, adicione o código de ativação cors como mostrado abaixo.

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

Para mais informações: consulte este

Arshath Shameer
fonte
0

Use um Atributo de Ação / Controlador personalizado para definir os cabeçalhos do CORS.

Exemplo:

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
    }
}

Em seguida, no Web API Controller / Action:

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

Apenas para adicionar uma resposta aqui, se você estiver usando app.UseHttpsRedirection()e não estiver acessando a porta SSL, considere comentar isso.

Raj
fonte
0

Eu estava usando o blazor webassembly como cliente e o asp.net web api core como back-end e também tive problemas com o cors.

Encontrei solução com estes códigos:

As primeiras linhas da API do núcleo da API do ASP.Net Startup.cs ConfigureServices e Configure são assim:

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

 //other code below...
}

e meu método Configure:

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

mude http://example.comcom o domínio do cliente ou endereço IP

Zviadi
fonte
-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
fonte
Edite sua resposta para incluir e explicar seu código e como ele difere das outras respostas. Isso fará com que o seu post mais útil e mais provável para que seja upvoted :)
Das_Geek