wake-up-neo.net

ASP.NET Core CORS-Anforderung blockiert; Warum wendet meine API nicht die richtigen Header an?

Versuch, CORS mit Authentifizierung einzurichten. Ich habe eine Web-API-Site unter http: // localhost: 61000 und eine aufwendige Webanwendung unter http: // localhost: 62000 . In der Web-API-Startup.cs habe ich:

 public void ConfigureServices(IServiceCollection services)
 {
        services.AddCors(o => o.AddPolicy("MyPolicy", corsBuilder =>
        {
            corsBuilder.WithOrigins("http://localhost:62000")
                .AllowAnyMethod()
                .AllowAnyHeader()
                .AllowCredentials();
        }));
        IMvcBuilder builder = services.AddMvc();
        // ...
}

// ...

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
        app.UseCors("MyPolicy");
        app.UseDeveloperExceptionPage();
        app.UseDefaultFiles();
        app.UseStaticFiles();
        app.UseMvc();
}

All die Verdoppelung scheint zu zeigen, dass alles sein sollte, was ich brauche. Im Javascript meiner App rufe ich an:

    $.ajax({
        type: 'POST',
        url: "http://localhost:61000/config/api/v1/MyStuff",
        data: matchForm.serialize(),
        crossDomain: true,
        xhrFields: { withCredentials: true },
        success: function (data) {
            alert(data);
        }
    });

Und ich bekomme in Chrome: Failed to load http://localhost:61000/config/api/v1/MyStuff: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:62000' is therefore not allowed access.

... und in Firefox: Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at http://localhost:61000/config/api/v1/MyStuff. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing). 

Was vermisse ich? Das sollte alles sein, was ich brauche, um CORS zu aktivieren, dachte ich, aber klar, es fehlt noch etwas.

4

Es scheint, dass ein Fehler in meinem Code aufgetreten ist, aber ich habe den dunklen Fehler bemerkt, anstatt eine von ASP.NET generierte Fehlerseite zu erhalten. Es stellt sich heraus, dass die CORS-Header in der Tat zuerst richtig angewendet wurden, , aber dann von allen durch ASP.NET-Middleware generierten Fehlern entfernt werden. Siehe auch https://github.com/aspnet/Home/issues/2378 .

Ich habe diesen Link verwendet, um diese Klasse herauszufinden

using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;

namespace MySite.Web.Middleware
{
    /// <summary>
    /// Reinstates CORS headers whenever an error occurs.
    /// </summary>
    /// <remarks>ASP.NET strips off CORS on errors; this overcomes this issue,
    ///  explained and worked around at https://github.com/aspnet/Home/issues/2378 </remarks>
    public class MaintainCorsHeadersMiddleware
    {
        public MaintainCorsHeadersMiddleware(RequestDelegate next)
        {
            _next = next;
        }
        private readonly RequestDelegate _next;

        public async Task Invoke(HttpContext httpContext)
        {
            // Find and hold onto any CORS related headers ...
            var corsHeaders = new HeaderDictionary();
            foreach (var pair in httpContext.Response.Headers)
            {
                if (!pair.Key.ToLower().StartsWith("access-control-")) { continue; } // Not CORS related
                corsHeaders[pair.Key] = pair.Value;
            }

            // Bind to the OnStarting event so that we can make sure these CORS headers are still included going to the client
            httpContext.Response.OnStarting(o => {
                var ctx = (HttpContext)o;
                var headers = ctx.Response.Headers;
                // Ensure all CORS headers remain or else add them back in ...
                foreach (var pair in corsHeaders)
                {
                    if (headers.ContainsKey(pair.Key)) { continue; } // Still there!
                    headers.Add(pair.Key, pair.Value);
                }
                return Task.CompletedTask;
            }, httpContext);

            // Call the pipeline ...
            await _next(httpContext);
        }
    }
}

Und dann habe ich es zu meiner Site-Konfiguration in Startup.cs hinzugefügt:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        app.UseCors(...);
        app.UseMiddleware<MaintainCorsHeadersMiddleware>();

        ...
        app.UseMvc();
    }
4

In meinem Fall gingen die CORS-Header verloren, weil ich eine Anforderung vom Typ "application/json" abgab. In CORS senden diese Art von Anforderung zuerst eine OPTIONS-Methode. Danach wird die reguläre POST angefordert. Die OPTIONS wurden jedoch durch einen Middleware-Code in meiner .Net Core-Pipeline mit folgendem Code verwaltet:

        if (context.Request.Method == "OPTIONS")
        {
            context.Response.StatusCode = (int)HttpStatusCode.OK;
            await context.Response.WriteAsync(string.Empty);
        } 

Sobald ich die Middleware entfernt habe, waren diese Anfragen einwandfrei. 

0
Fidel Orozco

Antwort von ASP.NET Core 2.2.0

Dieses Problem ist jetzt behoben . CORS-Header werden jetzt auch zurückgegeben, wenn Ausnahmen ausgelöst werden und eine Antwort von 500 zurückgegeben wird.

ASP.NET Core <= 2.1.0 Antwort

CORS-Header wurden aus der Antwort entfernt, wenn eine Ausnahme ausgelöst wurde und eine Antwort von 500 zurückgegeben wurde.

Ich hatte das gleiche Problem bei einem Web-API-Projekt mit OWIN-Middleware, bei dem eine falsche Paketversion Fehler auf der API-Seite verursachte (auf der Clientseite ausgeblendet, weil CORS-Header in der Antwort entfernt wurden, wodurch der ursprüngliche Fehler verdeckt wurde). Ich habe eine ähnliche Lösung wie Ihre implementiert und hier geteilt, weil ich mit OWIN kein ähnliches Beispiel im Web finden konnte:

using System;
using System.Linq;
using System.Threading.Tasks;
using Owin;
using Microsoft.Owin;
using Microsoft.Owin.Cors;

namespace App_Server
{
    using AppFunc = Func<IDictionary<string, object>, Task>;
    partial class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseCors(CorsOptions.AllowAll);
            app.Use(new Func<AppFunc, AppFunc>(RetainHeaders));
            ....
            (other startup tasks)
        }

        private AppFunc RetainHeaders(AppFunc next)
        {
            AppFunc appFunc = async (IDictionary<string, object> context) =>
            {
                IOwinContext httpContext = new OwinContext(context);
                var corsHeaders = new HeaderDictionary(new Dictionary<string, string[]>());

                foreach (var pair in httpContext.Response.Headers)
                {
                    if (!pair.Key.ToLower().StartsWith("access-control-")) { continue; } //not a CORS header
                    corsHeaders[pair.Key] = pair.Value.First();
                }

                httpContext.Response.OnSendingHeaders(o =>
                {
                    var localcontext = new OwinContext((IDictionary<string, object>)o);
                    var headers = localcontext.Response.Headers;
                    //make sure headers are present, and if not, add them back
                    foreach (var pair in corsHeaders)
                    {
                        if (headers.ContainsKey(pair.Key)) { continue; }
                        headers.Add(pair.Key, pair.Value);
                    }
                }, context);

                await next.Invoke(context);
            };
            return appFunc;
        }
}

Angesichts der unzureichenden Dokumentation der OWIN-Pakete für .Net war dies ein ziemlicher Prozess, und ich hoffe, dass er jemandem hilft, der darauf stößt, nach einer Lösung zu suchen.

0
Ryan I.