Comment activer CORS dans ASP.net Core WebAPI

190

Ce que j'essaye de faire

J'ai une API Web principale ASP.Net Core hébergée sur un plan gratuit Azure (code source: https://github.com/killerrin/Portfolio-Backend ).

J'ai également un site Web client que je souhaite faire consommer cette API. L'application cliente ne sera pas hébergée sur Azure, mais sera plutôt hébergée sur des pages Github ou sur un autre service d'hébergement Web auquel j'ai accès. Pour cette raison, les noms de domaine ne s'aligneront pas.

En regardant cela, je dois activer CORS du côté de l'API Web, mais j'ai essayé à peu près tout pendant plusieurs heures maintenant et il refuse de fonctionner.

Comment j'ai la configuration du client C'est juste un simple client écrit en React.js. J'appelle les API via AJAX dans Jquery. Le site React fonctionne donc je sais que ce n'est pas ça. L'appel de l'API Jquery fonctionne comme je l'ai confirmé dans la tentative 1. Voici comment je passe les appels

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

Ce que j'ai essayé


Tentative 1 - La `` bonne '' manière

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

J'ai suivi ce didacticiel sur le site Web de Microsoft jusqu'à un T, en essayant les 3 options pour l'activer globalement dans Startup.cs, en le configurant sur chaque contrôleur et en l'essayant à chaque action.

En suivant cette méthode, le Cross Domain fonctionne, mais uniquement sur une seule Action sur un seul contrôleur (POST sur le AccountController). Pour tout le reste, le Microsoft.AspNetCore.Corsmiddleware refuse de définir les en-têtes.

J'ai installé Microsoft.AspNetCore.Corsvia NUGET et la version est1.1.2

Voici comment je l'ai configuré dans 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();

        ...
        ...
        ...
    }

Comme vous pouvez le voir, je fais tout comme dit. J'ajoute Cors avant MVC les deux fois, et quand cela n'a pas fonctionné, j'ai essayé de mettre [EnableCors("MyPolicy")]chaque contrôleur comme tel

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

Tentative 2 - Brute le forçant

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

Après plusieurs heures d'essais sur la tentative précédente, j'ai pensé que j'essaierais de le forcer brutalement en essayant de définir les en-têtes manuellement, les forçant à s'exécuter à chaque réponse. J'ai fait cela en suivant ce tutoriel sur la façon d'ajouter manuellement des en-têtes à chaque réponse.

Ce sont les en-têtes que j'ai ajoutés

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

Ce sont d'autres en-têtes que j'ai essayés qui ont échoué

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

Avec cette méthode, les en-têtes Cross Site sont correctement appliqués et ils apparaissent dans ma console développeur et dans Postman. Le problème est cependant que, même s'il réussit le Access-Control-Allow-Origintest, le navigateur Web lance un ajustement sifflant (je crois)Access-Control-Allow-Headers indiquant415 (Unsupported Media Type)

Donc, la méthode de la force brute ne fonctionne pas non plus


finalement

Quelqu'un a-t-il réussi à faire fonctionner cela et pourrait-il donner un coup de main, ou simplement être en mesure de me diriger dans la bonne direction?


ÉDITER

Donc, pour faire passer les appels d'API, j'ai dû arrêter d'utiliser JQuery et passer au XMLHttpRequestformat Pure Javascript .

Tentative 1

J'ai réussi à faire Microsoft.AspNetCore.Corsfonctionner le en suivant la réponse de MindingData, sauf dans la Configureméthode mettant l' app.UseCorsavant app.UseMvc.

De plus, lorsqu'il est mélangé avec la solution API Javascript options.AllowAnyOrigin() pour la prise en charge des caractères génériques, il a également commencé à fonctionner.

Tentative 2

J'ai donc réussi à faire fonctionner Attempt 2 (force brute) ... à la seule exception que le Wildcard pour Access-Control-Allow-Originne fonctionne pas et que je dois donc définir manuellement les domaines qui y ont accès.

Ce n'est évidemment pas idéal puisque je veux juste que cette WebAPI soit largement ouverte à tout le monde, mais cela fonctionne au moins pour moi sur un site séparé, ce qui signifie que c'est un début

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
la source
2
Pour votre 415 (Unsupported Media Type)problème, définissez un en- Content-Typetête de demande sur application/json.
Technetium
5
Merci d'avoir pris le temps d'écrire une question aussi descriptive.
user1007074
1
Si vous testez avec Postman, assurez-vous de définir Origin sur * ou quelque chose pour l'en-tête de la demande, alors la tentative # 1 devrait fonctionner. Sans cet en-tête, Access-Control-Allow-Origin ne sera pas renvoyé dans l'en-tête de réponse.
tala9999

Réponses:

240

Parce que vous avez une stratégie CORS très simple (Autoriser toutes les demandes du domaine XXX), vous n'avez pas besoin de la compliquer. Essayez d'abord de faire ce qui suit (une implémentation très basique de CORS).

Si vous ne l'avez pas déjà fait, installez le package CORS nuget.

Install-Package Microsoft.AspNetCore.Cors

Dans la méthode ConfigureServices de votre startup.cs, ajoutez les services CORS.

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

Ensuite, dans votre méthode Configure de votre startup.cs, ajoutez ce qui suit:

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

Maintenant, essayez. Les politiques sont utilisées lorsque vous voulez des politiques différentes pour différentes actions (par exemple, différents hôtes ou différents en-têtes). Pour votre exemple simple, vous n'en avez vraiment pas besoin. Commencez par cet exemple simple et modifiez-le selon vos besoins à partir de là.

Lectures complémentaires: http://dotnetcoretutorials.com/2017/01/03/enabling-cors-asp-net-core/

MindingData
la source
3
XMLHttpRequest ne peut pas charger andrewgodfroyportfolioapi.azurewebsites.net/api/Authentication . La réponse à la demande de contrôle en amont ne passe pas la vérification de contrôle d'accès: aucun en-tête «Access-Control-Allow-Origin» n'est présent sur la ressource demandée. L' accès à l' origine ' localhost: 3000 ' n'est donc pas autorisé. La réponse avait le code d'état HTTP 415.
killerrin
7
Il est peu probable que cela fonctionne lorsque vous vous inscrivez app.UseCors APRÈS `` app.UseMvc () ''. Les middlewares sont exécutés dans l'ordre dans lequel ils sont enregistrés
Tseng
24
en utilisant app.UseCors avant app.UseMvc, dans la méthode Configure semble fonctionner. Pour une raison quelconque, la séquence semble avoir de l'importance.
MrClan
1
Pour moi, le plus gros problème de CORS dans 2.0 est qu'il ne dit pas ce qui ne va pas, mais échoue silencieusement à définir les en-têtes CORS. Remarque : n'oubliez pas d'ajouter tous vos en-têtes requis à la stratégie ou cela échouera (j'avais le type de contenu). Aussi étrange pour moi que le middleware CORS ne freine pas le traitement des requêtes, il informe simplement dans les logs que l'origine n'est pas autorisée et ... Passe la requête plus loin (l'ordre du middleware était correct).
Andrii M4n0w4R
2
J'ai dû activer options.DisableHttpsRequirement();pour que tout cela fonctionne. Il semble qu'avec les paramètres https cors ne s'appliquaient pas.
Michael Brown
210
  • Dans ConfigureServices, ajoutez services.AddCors(); AVANT les services.AddMvc ();

  • Ajouter UseCors dans Configure

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

Le point principal est cet ajout app.UseCors, avant app.UseMvc().

Assurez-vous de déclarer la fonctionnalité CORS avant MVC afin que le middleware se déclenche avant que le pipeline MVC n'obtienne le contrôle et mette fin à la demande.

Une fois que la méthode ci-dessus fonctionne, vous pouvez la modifier, configurer une ORIGINE spécifique pour accepter les appels d'API et éviter de laisser votre API si ouverte à tout le monde

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

    services.AddMvc();
}

Dans la méthode configure, indiquez à CORS d'utiliser la stratégie que vous venez de créer:

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

Je viens de trouver cet article compact sur le sujet - https://dzone.com/articles/cors-in-net-core-net-core-security-part-vi

Ji Ra
la source
1
Cela fonctionne pour moi. codeproject.com/Articles/1150023/...
hubert17
17
Cela devrait vraiment obtenir plus de votes positifs comme bon point de départ. D'après mon expérience de plus de 25 ans de codage, il est toujours agréable de savoir comment ouvrir les vannes pour s'assurer que cela "fonctionne", puis fermer / sécuriser les choses si nécessaire.
Indy-Jones
4
Juste pour mentionner cela, contrairement à Configure()l'ordre n'est pas vraiment important ici à l'intérieurConfigureServices()
B12Toaster
J'ai utilisé le lien dans le lecteur supplémentaire et ces étapes ont résolu cette erreur. Je ne savais pas où ces changements devaient être placés (je pensais que l'API). Le lien a confirmé qu'ils devraient être placés dans l'API. Merci pour l'aide. Je faisais totalement tourner mes roues avec cette erreur.
Richard
1
FYI - La spécification CORS indique également que la définition des origines sur "*" (toutes les origines) n'est pas valide si l'en-tête Access-Control-Allow-Credentials est présent. Autrement dit, vous ne pouvez pas utiliser AllowCredentials()avec AllowAnyOrigin()comme ci - dessus. Pour utiliser, AllowCredentials()vous devez définir WithOrigins(). docs.microsoft.com/en-us/aspnet/core/security/…
Nick De Beer
28

J'ai créé ma propre classe middleware qui a fonctionné pour moi, je pense qu'il y a quelque chose qui ne va pas avec la classe 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>();
    }
}

et l'a utilisé de cette façon dans startup.cs

app.UseCorsMiddleware();
user8266077
la source
Manière très élégante d'exécuter Access-Control-Allow-Origin.
Artur Poniedziałek
Cela fonctionne sur WebAPI et MVC et n'a pas de dépendances, merci!
Joe
J'étais sceptique à ce sujet également, mais cela a fonctionné pour moi. J'ai essayé pratiquement toutes les autres méthodes pour y parvenir que je pouvais trouver sur Internet, mais peu importe ce que le serveur ne répondrait pas avec les en-têtes d'accès. Cela a très bien fonctionné. J'utilise aspnetcore 2.1.
Jordan
Vous ne devez renvoyer les en-têtes cors que si le client envoie l'en-tête "Origin" dans la demande. Dans CospMiddleware original, il ressemble à ceci:if (!context.Request.Headers.ContainsKey(CorsConstants.Origin)) return this._next(context);
Andrew Prigorshnev
2
Peut-être "quelque chose ne va pas avec la classe middleware .net core" parce que vous n'ajoutez simplement pas d'en-tête "Origin" lorsque vous le testez avec curl ou quelque chose comme ça. Les navigateurs ajoutent cet en-tête automatiquement lorsque vous faites une demande en code js.
Andrew Prigorshnev
18

Dans mon cas, seule la getdemande fonctionne bien selon la réponse de MindingData. Pour les autres types de demande, vous devez écrire:

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

N'oubliez pas d'ajouter .AllowAnyHeader()

Towhid
la source
Acceptez avec Towhid que AllowAnyHeader () est nécessaire. Il permet au serveur de recevoir la requête OPTIONS si la requête de HEADER manque quelque chose.
Rivon
Le .AllowAnyHeader () l'a fait pour moi, j'ai eu des problèmes avec la réponse de contrôle en amont.
takaz
11

Pour développer la réponse de user8266077 , j'ai trouvé que je devais toujours fournir une réponse OPTIONS pour les demandes de contrôle en amont dans .NET Core 2.1-preview pour mon cas d'utilisation:

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

puis activé le middleware comme ça dans Startup.cs

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
  app.UseMiddleware(typeof(CorsMiddleware));
  // ... other middleware inclusion such as ErrorHandling, Caching, etc
  app.UseMvc();
}
ckr
la source
1
Je recommande d'ajouter un middleware de cette façon:app.Use<CorsMiddleware>();
Albert221
Vous pouvez remplacer ces 2 lignes: context.Response.StatusCode = (int) HttpStatusCode.OK; attendez context.Response.WriteAsync (string.Empty); avec un simple: retour;
Hayha
1
Pour développer votre expansion de la réponse de @ user8266077: Attention, si la requête échoue pour une autre raison, ce middleware lèvera une exception et les en-têtes ne seront pas définis. Cela signifie qu'en frontend, cela ressemblera toujours à un problème CORS même si c'est quelque chose de totalement différent. J'ai contourné cela en détectant toutes les exceptions await _next(context)et en définissant manuellement le code d'état et la réponse si cela se produit. J'ai également dû ajouter «autorisation» à Access-Control-Allow-Headers pour que la demande de contrôle en amont fonctionne lors des demandes de React qui nécessitent une autorisation.
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 Genèse
la source
.SetIsOriginAllowed ((host) => true) l'a résolu pour moi.
JensB
wow, donc je m'attendais pleinement à ce que l'une des autres réponses fonctionne avant ce petit avec seulement 3 votes. mais j'ai méticuleusement essayé chacun d'eux, ... sur un coup de tête, j'ai choisi le vôtre et ça a marché. merci
roberto tomás le
C'est celui qui a fonctionné pour moi sur .NET Core 3.1 pour autoriser à peu près tout.
JustinHui
10

J'avais du mal avec ça pendant DAYS.

J'ai finalement réussi à le faire fonctionner en passant app.UseCors(CORS_POLICY);au TOP de Configure().

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

Assurez-vous de déclarer la fonctionnalité CORS avant> MVC car les en-têtes doivent être appliqués avant que MVC termine la demande.

<= Même si mon application n'a pas appelé UseMVC(), le déplacement UseCors()vers le haut a résolu le problème

Aussi:

  • Microsoft.AspNetCore.CorsAuparavant, il s'agissait d'un package NuGet requis dans .Net Core 2 et versions antérieures; il fait désormais automatiquement partie de Microsoft.AspNetCore dans .Net Core 3 et supérieur.
  • builder.AllowAnyOrigin() et .AllowCredentials() options CORS sont désormais mutuellement exclusives dans .Net Core 3 et supérieur
  • La politique CORS semble exiger un appel Angular au serveur avec https. Une URL http semblait donner une erreur CORS quelle que soit la configuration CORS du serveur .Net Core. Par exemple, http://localhost:52774/api/Contactsdonnerait une erreur CORS; il suffit de changer l'URL en https://localhost:44333/api/Contactsfonctionnant.

Remarque supplémentaire :

Dans mon cas, CORS ne fonctionnerait pas tant que je ne suis pas passé app.UseCors()au dessus app.UseEndpoints(endpoints => endpoints.MapControllers()).

Jour brumeux
la source
2
Celui-ci devrait être la réponse si vous utilisez Net Core 3. Merci de m'avoir sauvé la vie!
Canada Wan le
2
"Avec le routage des points de terminaison, le middleware CORS doit être configuré pour s'exécuter entre les appels à UseRouting et UseEndpoints. Une configuration incorrecte entraînera l'arrêt du middleware." ici docs.microsoft.com/en-us/aspnet/core/security/…
Mark Schultheiss
"Avec le routage des points de terminaison, le middleware CORS doit être configuré pour s'exécuter entre les appels à UseRouting et UseEndpoints. Une configuration incorrecte entraînera l'arrêt du middleware." ici docs.microsoft.com/en-us/aspnet/core/security/…
Mark Schultheiss
7

Aucune des procédures ci-dessus n'a aidé et j'ai ensuite lu l' article qui a résolu le problème.

Ci-dessous le code.

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

et

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

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

et en plus de ma méthode d'action

[EnableCors("CorsPolicy")]
Sainath
la source
2
C'est probablement une mauvaise idée: vous ne devriez pas mélanger le middleware ( app.UseCors()) avec [EnableCors()]dans la même application. Vous devez utiliser l'un ou l'autre - mais pas les deux: docs.microsoft.com/en-us/aspnet/core/security/… :Use the [EnableCors] attribute or middleware, not both in the same app.
FoggyDay
4

essayez d'ajouter jQuery.support.cors = true;avant l'appel Ajax

Il se peut également que les données que vous envoyez à l'API soient bancales,

essayez d'ajouter la fonction JSON suivante

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

puis dans vos données: objet changez-le en

    data: JSON.stringify({
        username: username,
        password: password
    }),
Riaan Saayman
la source
Merci de votre aide. Certainement utilisé une partie de la réponse pour trouver la solution à la fin après avoir combiné les réponses de tout le monde
killerrin
4

La solution la plus simple est d'ajouter

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

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

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

à Startup.cs.

amilamad
la source
3

Je pense que si vous utilisez votre propre middleware CORS, vous devez vous assurer qu'il s'agit bien d'une requête CORS en vérifiant l'en- tête d' origine .

 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
la source
Merci beaucoup. Je suis presque devenu fou, me demandant pourquoi l'en- Access-Control-Allow-Origintête n'a pas été émis par le serveur. En fait, j'ai envoyé des demandes via Postman sans l'en- Origintête. Cela m'a sauvé la journée! (Ou au moins ma matinée;))
Paul Kertscher
2

Sur la base de votre commentaire dans la réponse de MindingData, cela n'a rien à voir avec votre CORS, cela fonctionne bien.

L'action de votre contrôleur renvoie les mauvaises données. HttpCode 415 signifie "Type de support non pris en charge". Cela se produit lorsque vous passez le mauvais format au contrôleur (c'est-à-dire XML à un contrôleur qui n'accepte que json) ou lorsque vous retournez un type incorrect (retournez Xml dans un contrôleur qui est déclaré pour ne renvoyer que xml).

Pour plus tard, vérifiez l'existence de l' [Produces("...")]attribut sur votre action

Tseng
la source
Merci de votre aide. J'ai essayé une nouvelle solution et joué avec json envoyé et cela a fonctionné après que je l'ai stringifié et que cela fonctionne
killerrin
2

Pour moi, cela n'avait rien à voir avec le code que j'utilisais. Pour Azure, nous devions entrer dans les paramètres de l'App Service, dans le menu latéral l'entrée "CORS". Là, j'ai dû ajouter le domaine à partir duquel je demandais des choses. Une fois que j'ai eu ça, tout était magique.

kjbetz
la source
2

Dans launchSettings.json, sous iisSettings, définissez anonymousAuthentication sur true:

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

Ensuite, dans Startup.cs, sous ConfigureServices, avant services.AddMvc, ajoutez:

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

puis, dans la méthode configure, avant app.UseMvc () ajouter:

app.UseCors("ApiCorsPolicy");
Adrian
la source
Cela l'a fait pour moi, j'ai initialement configuré mon projet pour l'authentification Windows, mais j'ai ensuite dû le changer en anonyme, j'avais CORS correctement configuré mais ce paramètre dans launchSettings.json était le coupable, merci de poster cela !.
HaRoLD
2

J'utilise .Net CORE 3.1 et j'ai passé des années à me cogner la tête contre un mur avec celui-ci quand j'ai réalisé que mon code avait commencé à fonctionner mais que mon environnement de débogage était cassé, alors voici 2 conseils si vous essayez de résoudre le problème. problème:

  1. Si vous essayez de consigner les en-têtes de réponse à l'aide du middleware ASP.NET, l'en-tête "Access-Control-Allow-Origin" n'apparaîtra jamais, même s'il y est. Je ne sais pas comment mais il semble être ajouté en dehors du pipeline (à la fin, j'ai dû utiliser WireShark pour le voir).

  2. .NET CORE n'enverra pas "Access-Control-Allow-Origin" dans la réponse à moins que vous n'ayez un en-tête "Origin" dans votre demande. Postman ne le définira pas automatiquement, vous devrez donc l'ajouter vous-même.

Andy
la source
2

Dans mon cas, j'ai corrigé avec UseCors avant UserRouting ..

René Bizelli de Oliveira
la source
J'ai rencontré quelque chose de similaire lorsque j'ai mis à niveau de dotnet core 2.2 vers 3.1. J'ai dû déplacer app.UseCors () au-dessus de app.UseRouting (). Cette réponse m'a orienté dans la bonne direction.
Brandonm
1

.NET Core 3.1

A travaillé pour moi et comment les documents disent de le faire:

dans la classe de démarrage:

readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins"; 

Dans la méthode ConfigureServices ():

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

Dans la méthode Configure ():

    app.UseCors(MyAllowSpecificOrigins);  

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

Andrew
la source
0

J'ai obtenu la réponse de MindingData ci-dessus pour fonctionner, mais j'ai dû utiliser Microsoft.AspNet.Cors au lieu de Microsoft.AspNetCore.Cors. J'utilise le projet d'API d'application Web .NetCore dans Visual Studio 2019

Carl
la source
2
REMARQUE: vous ne devez pas utiliser Microsoft.AspNet.Cors dans une application ASP.Net Cor. Si vous utilisez .Net Core 3.0 ou version ultérieure, vous n'avez pas du tout besoin d'importer de package NuGet pour CORS. Si vous utilisez .Net Core 2.3 ou une version antérieure, vous avez besoin de la version appropriée de Microsoft.AspNet.Cors de NuGet.
FoggyDay
0

le

Microsoft.AspNetCore.Cors

vous permettra de faire CORS avec des fonctionnalités intégrées, mais il ne gère pas la demande OPTIONS. La meilleure solution de contournement à ce jour est de créer un nouveau middleware, comme suggéré dans un article précédent. Vérifiez la réponse marquée comme correcte dans le post suivant:

Activer l'en-tête OPTIONS pour CORS sur l'API Web .NET Core

Bonomi
la source
0

Un moyen simple et facile de le faire.

  1. Installer le paquet

Install-Package Microsoft.AspNetCore.Cors

  1. Mettez ce code ci-dessous dans le fichier startup.cs

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

pintu sharma
la source
0

Voici mon code :)

  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
la source
0

Voici comment j'ai fait cela.

Je vois que dans certaines réponses, ils établissent app.UserCors("xxxPloicy")et installent des [EnableCors("xxxPloicy")]contrôleurs. Vous n'avez pas besoin de faire les deux.

Voici les étapes.

Dans Startup.cs à l'intérieur des ConfigureServices, ajoutez le code suivant.

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

Si vous souhaitez appliquer partout dans le projet, ajoutez le code suivant dans la méthode Configure dans Startup.cs

app.UseCors("xxxPolicy");

Ou

Si vous souhaitez l'ajouter aux contrôleurs spécifiques, ajoutez le code d'activation des cors comme indiqué ci-dessous.

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

Pour plus d'informations: voir ceci

Arshath Shameer
la source
0

Utilisez un attribut Action / Controller personnalisé pour définir les en-têtes CORS.

Exemple:

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

Puis sur le contrôleur / action de l'API Web:

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

Juste pour ajouter une réponse ici, si vous utilisez app.UseHttpsRedirection(), et que vous ne frappez pas le port SSL, envisagez de commenter ceci.

Raj
la source
0

J'utilisais blazor webassembly comme client et asp.net web api core comme backend et j'avais aussi un problème de cors.

J'ai trouvé une solution avec ce code:

Mon ASP.Net core web api Startup.cs ConfigureServices et Configure les méthodes premières lignes ressemble à ceci:

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

 //other code below...
}

et ma méthode Configure:

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

changer http://example.comavec votre domaine client ou votre adresse IP

Zviadi
la source
-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
la source
Veuillez modifier votre réponse pour inclure et expliquer votre code et en quoi il diffère des autres réponses. Cela rendra votre message plus utile et plus susceptible d'être voté :)
Das_Geek