it-swarm.com.de

So aktivieren Sie CORS in ASP.net Core WebAPI

Was ich versuche zu tun

Ich habe eine ASP.Net Core-Web-API für das Back-End, die auf einem Azure Free-Plan gehostet wird (Quellcode: https://github.com/killerrin/Portfolio-Backend ).

Ich habe auch eine Client-Website, von der ich möchte, dass sie diese API verwendet. Die Clientanwendung wird nicht auf Azure gehostet, sondern auf Github Pages oder einem anderen Webhostingdienst, auf den ich Zugriff habe. Aus diesem Grund werden die Domain-Namen nicht ausgerichtet.

In diesem Zusammenhang muss ich CORS auf der Web-API-Seite aktivieren. Ich habe jedoch seit mehreren Stunden so gut wie alles ausprobiert und es lehnt es ab, zu funktionieren.

Wie ich das Client-Setup habe Es ist nur ein einfacher Client, der in React.js geschrieben ist. Ich rufe die APIs über AJAX in Jquery auf. Die Seite React funktioniert, daher weiß ich, dass es nicht so ist. Der Jquery-API-Aufruf funktioniert wie in Versuch 1 bestätigt. So tätige ich die Aufrufe

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

Was ich ausprobiert habe


Versuch 1 - Der "richtige" Weg

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

Ich habe dieses Tutorial auf der Microsoft-Website zu einem T gefolgt, indem ich alle drei Optionen ausprobiert habe, um es global in Startup.cs zu aktivieren, es auf jedem Controller einzurichten und es bei jeder Aktion zu testen.

Nach dieser Methode funktioniert die Cross Domain, jedoch nur für eine einzelne Aktion auf einem einzelnen Controller (POST an den AccountController). Für alles andere weigert sich die Middleware Microsoft.AspNetCore.Cors, die Header zu setzen.

Ich habe Microsoft.AspNetCore.Cors über NUGET installiert und die Version ist 1.1.2

Hier ist, wie ich es in Startup.cs eingerichtet habe

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

        ...
        ...
        ...
    }

Wie Sie sehen, mache ich alles wie gesagt. Ich füge Cors vor MVC beide Male hinzu, und als das nicht funktionierte, habe ich versucht, [EnableCors("MyPolicy")] auf jeden Controller so zu setzen

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

Versuch 2 - Brute Forcing it

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

Nachdem ich den vorherigen Versuch einige Stunden lang durchgearbeitet hatte, stellte ich mir vor, ich würde versuchen, ihn zu brachialisieren, indem ich versuchte, die Header manuell festzulegen, sodass sie bei jeder Antwort ausgeführt werden mussten. Ich habe dies im Anschluss an dieses Tutorial getan, um zu erfahren, wie jeder Antwort manuell Überschriften hinzugefügt werden.

Dies sind die Überschriften, die ich hinzugefügt habe

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

Dies sind andere Header, die ich ausprobiert habe und die fehlgeschlagen sind

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

Bei dieser Methode werden die Cross Site-Header ordnungsgemäß angewendet und in meiner Entwicklerkonsole und in Postman angezeigt. Das Problem ist jedoch, dass der Webbrowser, während er die Prüfung für Access-Control-Allow-Origin besteht, eine zischende Passform für Access-Control-Allow-Headers ausgibt, die 415 (Unsupported Media Type) angibt.

Die Brute-Force-Methode funktioniert also auch nicht


Endlich

Hat jemand damit angefangen und könnte helfen oder mich einfach in die richtige Richtung lenken?


EDIT

Um die API-Aufrufe zu verarbeiten, musste ich die Verwendung von JQuery beenden und in ein reines Javascript XMLHttpRequest-Format wechseln.

Versuch 1

Ich habe es geschafft, den Microsoft.AspNetCore.Cors zum Funktionieren zu bringen, indem ich MindingDatas Antwort befolgt habe, außer in der Configure -Methode, bei der der app.UseCors vor dem app.UseMvc steht.

Darüber hinaus begann das Mischen mit der Javascript-API-Lösung options.AllowAnyOrigin() für die Unterstützung von Platzhaltern ebenfalls zu funktionieren.

Versuch 2

Also habe ich es geschafft, Attempt 2 (brute forcing it) zum Laufen zu bringen ... mit der einzigen Ausnahme, dass der Platzhalter für Access-Control-Allow-Origin nicht funktioniert und ich muss daher die Domänen, die Zugriff darauf haben, manuell einstellen .

Es ist offensichtlich nicht ideal, da ich möchte, dass dieses WebAPI für alle offen ist, aber es funktioniert zumindest für mich auf einer separaten Site, was bedeutet, dass es ein Anfang ist

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"));
122
killerrin

Da Sie eine sehr einfache CORS-Richtlinie haben (Alle Anfragen von XXX-Domains zulassen), müssen Sie diese nicht so kompliziert gestalten. Versuchen Sie zunächst Folgendes (Eine sehr grundlegende Implementierung von CORS).

Falls noch nicht geschehen, installieren Sie das CORS-Nuget-Paket.

Install-Package Microsoft.AspNetCore.Cors

Fügen Sie in der ConfigureServices-Methode Ihres startup.cs die CORS-Dienste hinzu.

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

Fügen Sie dann in Ihrer Configure-Methode Ihres startup.cs Folgendes hinzu:

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

Jetzt probieren Sie es aus. Richtlinien gelten für den Fall, dass Sie unterschiedliche Richtlinien für unterschiedliche Aktionen (z. B. unterschiedliche Hosts oder unterschiedliche Header) wünschen. Für dein einfaches Beispiel brauchst du es wirklich nicht. Beginnen Sie mit diesem einfachen Beispiel und optimieren Sie es nach Bedarf.

Weitere Informationen: http://dotnetcoretutorials.com/2017/01/03/enabling-cors-asp-net-core/

171
MindingData
  • Fügen Sie in ConfigureServices services.AddCors(); VOR services.AddMvc () hinzu;
  • UseCors hinzufügen in Konfigurieren

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

Der Hauptpunkt ist, dass app.UseCors vor app.UseMvc() hinzugefügt wird.

Stellen Sie sicher, dass Sie die CORS-Funktionalität vor MVC deklarieren, damit die Middleware ausgelöst wird, bevor die MVC-Pipeline die Steuerung übernimmt und die Anforderung beendet.

Nachdem die obige Methode funktioniert, können Sie sie so konfigurieren, dass sie API-Aufrufe akzeptiert und Ihre API nicht für andere offen lässt

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

In der configure-Methode weisen Sie CORS an, die soeben erstellte Richtlinie zu verwenden:

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

Ich habe gerade diesen kompakten Artikel zum Thema gefunden - https://dzone.com/articles/cors-in-net-core-net-core-security-part-vi

155
Ji Ra

Ich habe meine eigene Middleware-Klasse erstellt, die für mich funktioniert hat. Ich glaube, mit der .net-Core-Middleware-Klasse stimmt etwas nicht

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

und verwendet es auf diese Weise in der startup.cs

app.UseCorsMiddleware();
22
user8266077

In meinem Fall funktioniert nur die Anforderung get entsprechend der Antwort von MindingData. Für andere Arten von Anfragen müssen Sie schreiben:

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

Vergessen Sie nicht, .AllowAnyHeader() hinzuzufügen

14
Towhid

Um ser8266077 's answer zu erweitern, stellte ich fest, dass ich immer noch die Antwort OPTIONS für Preflight-Anforderungen in der .NET Core 2.1-Vorschau für angeben musste Mein Anwendungsfall:

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

und dann die Middleware wie in Startup.cs aktiviert

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
  app.UseMiddleware(typeof(CorsMiddleware));
  // ... other middleware inclusion such as ErrorHandling, Caching, etc
  app.UseMvc();
}
8
ckr

Keines der obigen Verfahren hat geholfen und ich habe dann article gelesen, wodurch das Problem behoben wurde.

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

und

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

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

und ganz oben auf meiner aktionsmethode

[EnableCors("CorsPolicy")]
5
Sainath

fügen Sie jQuery.support.cors = true; vor dem Ajax-Aufruf hinzu

Es kann auch sein, dass die Daten, die Sie an die API senden, wackelig sind.

fügen Sie die folgende JSON-Funktion hinzu

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

dann in deinen Daten: Objekt ändere es auf

    data: JSON.stringify({
        username: username,
        password: password
    }),
4
Riaan Saayman

Ich denke, wenn Sie Ihre eigene CORS Middleware verwenden, müssen Sie sicherstellen, dass es wirklich CORS angefordert wird, indem Sie die Herkunft prüfen Header.

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

Basierend auf Ihrem Kommentar in der Antwort von MindingData hat dies nichts mit Ihrem CORS zu tun. Es funktioniert einwandfrei.

Ihre Controller-Aktion gibt die falschen Daten zurück. HTTP-Code 415 bedeutet "Nicht unterstützter Medientyp". Dies passiert, wenn Sie entweder das falsche Format an den Controller übergeben (d. H. XML an einen Controller, der nur json akzeptiert) oder wenn Sie einen falschen Typ zurückgeben (Xml in einem Controller zurückgeben, der nur xml zurückgibt).

Für einen späteren Zeitpunkt überprüfen Sie die Existenz von [Produces("...")]attribute für Ihre Aktion

2
Tseng

Für mich hatte das nichts mit dem Code zu tun, den ich verwendete. Für Azure mussten wir in die Einstellungen des App Service gehen, im Seitenmenü den Eintrag "CORS". Dort musste ich die Domain hinzufügen, von der ich etwas angefordert hatte. Sobald ich das in mir hatte, war alles magisch.

2
kjbetz

Setzen Sie in launchSettings.json unter iisSettings anonymousAuthentication auf true:

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

Fügen Sie dann in Startup.cs unter ConfigureServices vor services.AddMvc Folgendes hinzu:

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

und dann fügen Sie in configure method vor app.UseMvc () Folgendes hinzu:

app.UseCors("ApiCorsPolicy");
1
Adrian

Einfachste Lösung ist hinzufügen

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

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

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

zu Startup.cs.

0
amilamad

Die obige Antwort von MindingData hat funktioniert, aber ich musste Microsoft.AspNet.Cors anstelle von Microsoft.AspNetCore.Cors verwenden. Ich verwende ein .NetCore-Webanwendungs-API-Projekt in Visual Studio 2019

0
carl