Jak włączyć CORS w programie ASP.net Core WebAPI

189

Co próbuję zrobić

Mam backend ASP.Net Core Web API hostowany na bezpłatnym abonamencie Azure (kod źródłowy: https://github.com/killerrin/Portfolio-Backend ).

Mam również witrynę kliencką, którą chcę używać w tym interfejsie API. Aplikacja kliencka nie będzie hostowana na platformie Azure, ale raczej będzie hostowana na stronach Github lub w innej usłudze hostingowej, do której mam dostęp. Z tego powodu nazwy domen nie będą się zgadzać.

Patrząc na to, muszę włączyć CORS po stronie Web API, jednak próbowałem już prawie wszystkiego od kilku godzin i to nie działa.

Jak mam skonfigurować klienta To tylko prosty klient napisany w React.js. Dzwonię do interfejsów API przez AJAX w Jquery. Strona React działa, więc wiem, że to nie to. Wywołanie interfejsu API Jquery działa tak, jak zostało to potwierdzone w Próbie 1. Oto jak wykonuję połączenia

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

Co próbowałem


Próba 1 - „Właściwa” droga

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

Wykonałem ten samouczek na stronie Microsoft do T, wypróbowując wszystkie 3 opcje włączania go Globalnie w pliku Startup.cs, konfigurowania go na każdym kontrolerze i wypróbowania go przy każdej akcji.

Zgodnie z tą metodą Cross Domain działa, ale tylko na pojedynczej akcji na jednym kontrolerze (POST do AccountController). W pozostałych przypadkach Microsoft.AspNetCore.Corsoprogramowanie pośrednie odmawia ustawienia nagłówków.

Zainstalowałem Microsoft.AspNetCore.Corsprzez NUGET, a wersja jest1.1.2

Oto jak mam to skonfigurować w 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();

        ...
        ...
        ...
    }

Jak widać, robię wszystko zgodnie z zaleceniami. Dwa razy dodawałem Corsę przed MVC, a kiedy to nie działało, próbowałem nałożyć [EnableCors("MyPolicy")]każdy kontroler jako taki

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

Próba 2 - brutalne zmuszanie

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

Po kilku godzinach próbowania poprzedniej próby, doszedłem do wniosku, że spróbuję go przerobić, próbując ręcznie ustawić nagłówki, zmuszając je do uruchomienia przy każdej odpowiedzi. Zrobiłem to po tym samouczku, w jaki sposób ręcznie dodawać nagłówki do każdej odpowiedzi.

To są nagłówki, które dodałem

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

To są inne nagłówki, które próbowałem i które zawiodły

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

Dzięki tej metodzie nagłówki Cross Site są poprawnie stosowane i pojawiają się w mojej konsoli programisty oraz w Postmanie. Problem jednak polega na tym, że gdy przeglądarka przechodzi Access-Control-Allow-Originpomyślnie, przeglądarka internetowa sycze pasuje (sądzę), Access-Control-Allow-Headersstwierdzając415 (Unsupported Media Type)

Więc metoda brutalnej siły też nie działa


Wreszcie

Czy ktoś doszedł do tego i mógł pomóc, czy po prostu wskazać mi właściwy kierunek?


EDYTOWAĆ

Aby uzyskać wywołania API, musiałem przestać używać JQuery i przejść na XMLHttpRequestformat czystego Javascript .

Próba 1

Udało mi się dostać Microsoft.AspNetCore.Corsdo pracy, postępując zgodnie z odpowiedzią MindingData, z wyjątkiem Configuremetody wstawiania app.UseCorswcześniej app.UseMvc.

Ponadto po zmieszaniu z JavaScript API Solution options.AllowAnyOrigin()do obsługi symboli wieloznacznych zaczęło działać.

Próba 2

Udało mi się więc sprawić, że próba 2 (brutalne zmuszanie) do działania ... z jedynym wyjątkiem, że Wildcard dla Access-Control-Allow-Originnie działa i jako taki muszę ręcznie ustawić domeny, które mają do niego dostęp.

Oczywiście nie jest idealny, ponieważ chcę, aby ten interfejs WebAPI był szeroko otwarty dla wszystkich, ale przynajmniej działa dla mnie na osobnej stronie, co oznacza, że ​​to początek

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
źródło
2
W przypadku 415 (Unsupported Media Type)problemu ustaw Content-Typenagłówek żądania na application/json.
Technetium
5
Dziękujemy za poświęcenie czasu na napisanie tak opisowego pytania.
user1007074,
1
Jeśli testujesz przy użyciu Listonosza, upewnij się, że ustawiłeś Origin na * lub coś w nagłówku żądania, wtedy Próba nr 1 powinna działać. Bez tego nagłówka Access-Control-Allow-Origin nie będzie zwracany w nagłówku odpowiedzi.
tala9999

Odpowiedzi:

238

Ponieważ masz bardzo prostą zasadę CORS (zezwalaj na wszystkie żądania z domeny XXX), nie musisz komplikować jej. Najpierw spróbuj wykonać następujące czynności (bardzo podstawowa implementacja CORS).

Jeśli jeszcze tego nie zrobiłeś, zainstaluj pakiet nuget CORS.

Install-Package Microsoft.AspNetCore.Cors

W metodzie ConfigureServices pliku startup.cs dodaj usługi CORS.

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

Następnie w metodzie Configure pliku startup.cs dodaj:

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

Teraz spróbuj. Zasady mają zastosowanie, gdy chcesz mieć różne zasady dla różnych działań (np. Różnych hostów lub różnych nagłówków). Dla prostego przykładu tak naprawdę go nie potrzebujesz. Zacznij od tego prostego przykładu i stamtąd dostosuj, jak trzeba.

Dalsza lektura: http://dotnetcoretutorials.com/2017/01/03/enabling-cors-asp-net-core/

MindingData
źródło
3
XMLHttpRequest nie może załadować andrewgodfroyportfolioapi.azurewebsites.net/api/Authentication . Odpowiedź na żądanie inspekcji wstępnej nie przechodzi kontroli kontroli dostępu: Żądany zasób nie zawiera nagłówka „Kontrola dostępu - Zezwalaj na pochodzenie”. W związku z tym źródło „ localhost: 3000 ” nie ma dostępu. Odpowiedź miała kod statusu HTTP 415.
killerrin
7
To raczej nie zadziała, gdy zarejestrujesz się app.UseCors PO `` app. UseMvc () `. Programy pośrednie są wykonywane w kolejności, w jakiej zostały zarejestrowane
Tseng
24
przy użyciu aplikacji UseCors przed aplikacją app. UseMvc wydaje się, że metoda Configure działa. Z jakiegoś powodu sekwencja wydaje się mieć znaczenie.
MrClan
1
Dla mnie największym problemem CORS w 2.0 jest to, że nie mówi, co jest nie tak, po prostu po cichu nie ustawiając nagłówków CORS. Uwaga : pamiętaj, aby dodać wszystkie wymagane nagłówki do zasad, bo to się nie powiedzie (miałem typ zawartości). Dziwne jest też dla mnie to, że oprogramowanie pośredniczące CORS nie hamuje przetwarzania żądań, po prostu informując w dziennikach, że pochodzenie jest niedozwolone i .. Przekazuje żądanie dalej (kolejność oprogramowania pośredniego była prawidłowa).
Andrii M4n0w4R
2
Musiałem włączyć options.DisableHttpsRequirement();, aby którykolwiek z tych elementów działał. Wygląda na to, że ustawienia https cors nie miały zastosowania.
Michael Brown
208
  • W ConfigureServices dodaj services.AddCors(); usługi PRZED usługą.AddMvc ();

  • Dodaj UseCors w Konfiguruj

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

Najważniejsze jest to, aby dodać app.UseCorswcześniej app.UseMvc().

Upewnij się, że zadeklarowałeś funkcjonalność CORS przed MVC, aby oprogramowanie pośredniczące zostało uruchomione, zanim potok MVC przejmie kontrolę i zakończy żądanie.

Po zadziałaniu powyższej metody możesz ją zmienić, skonfiguruj określony POCHODZENIE, aby akceptować wywołania interfejsu API i unikać pozostawiania interfejsu API tak otwartego dla każdego

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

    services.AddMvc();
}

W metodzie konfiguracji powiadom CORS, aby użył właśnie utworzonej zasady:

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

Właśnie znalazłem ten kompaktowy artykuł na ten temat - https://dzone.com/articles/cors-in-net-core-net-core-security-part-vi

Ji Ra
źródło
1
To działa dla mnie. codeproject.com/Articles/1150023/…
hubert17
17
To powinno naprawdę zyskać więcej głosów jako dobry punkt początkowy. Z mojego ponad 25-letniego doświadczenia w kodowaniu zawsze miło jest wiedzieć, jak otworzyć bramki, aby upewnić się, że faktycznie „działa”, a następnie zamykać / zabezpieczać rzeczy w razie potrzeby.
Indy-Jones,
4
Wystarczy wspomnieć o tym, w przeciwieństwie do Configure()kolejności, nie jest tu tak naprawdę ważneConfigureServices()
B12Toaster
Użyłem linku w dalszym czytniku i te kroki rozwiązały ten błąd. Nie byłem pewien, gdzie te zmiany powinny zostać umieszczone (pomyślałem, że API). Link potwierdził, że należy je umieścić w interfejsie API. Dzięki za pomoc. Z tym błędem obracałem całkowicie koła.
Richard
1
FYI - specyfikacja CORS stwierdza również, że ustawienie początków na „*” (wszystkie początki) jest nieprawidłowe, jeśli obecny jest nagłówek Access-Control-Allow-Credentials. Oznacza to, że nie możesz używać AllowCredentials()z AllowAnyOrigin()podobnymi powyżej. Aby użyć AllowCredentials(), musisz ustawić WithOrigins(). docs.microsoft.com/en-us/aspnet/core/security/…
Nick De Beer
28

Stworzyłem własną klasę oprogramowania pośredniego, która działała dla mnie, myślę, że coś jest nie tak z klasą oprogramowania pośredniego .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>();
    }
}

i użyłem go w ten sposób w pliku startup.cs

app.UseCorsMiddleware();
użytkownik8266077
źródło
Bardzo elegancki sposób uruchamiania Access-Control-Allow-Origin.
Artur Poniedziałek
Działa na WebAPI i MVC i nie ma żadnych zależności, dziękuję!
Joe
Byłem też sceptyczny, ale to zadziałało dla mnie. Próbowałem w zasadzie każdej innej metody, aby to osiągnąć, którą mogłem znaleźć w Internecie, ale bez względu na to, co serwer nie zareagowałby nagłówkami dostępu. To działało świetnie. Używam aspnetcore 2.1.
Jordan
Powinieneś zwrócić nagłówki cors tylko wtedy, gdy klient wyśle ​​nagłówek „Origin” w żądaniu. W oryginalnym CospMiddleware wygląda to następująco:if (!context.Request.Headers.ContainsKey(CorsConstants.Origin)) return this._next(context);
Andrew Prigorshnev
1
Może „coś jest nie tak z klasą oprogramowania pośredniego .net core”, ponieważ po prostu nie dodajesz nagłówka „Origin” podczas testowania go za pomocą curl lub coś takiego. Przeglądarki dodają ten nagłówek automatycznie po złożeniu żądania w kodzie js.
Andrew Prigorshnev
18

W moim przypadku tylko getżądanie działa dobrze zgodnie z odpowiedzią MindingData. W przypadku innych rodzajów wniosków musisz napisać:

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

Nie zapomnij dodać .AllowAnyHeader()

Towhid
źródło
Uzgodnij z Towhid, że AllowAnyHeader () jest potrzebny. Pozwala serwerowi otrzymać żądanie OPTIONS, jeśli w żądaniu HEADERA czegoś brakuje.
Rivon
Zrobił to dla mnie .AllowAnyHeader (), miałem problemy z odpowiedzią wstępną.
takaz
11

Aby rozwinąć na user8266077 „s odpowiedzi , znalazłem, że wciąż potrzebne do odpowiedzi opcjami dostaw dla inspekcji wstępnej wniosków w podstawowej .NET 2.1 Podgląd moim przypadku użycia:

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

a następnie włączył oprogramowanie pośrednie, tak jak w Startup.cs

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
  app.UseMiddleware(typeof(CorsMiddleware));
  // ... other middleware inclusion such as ErrorHandling, Caching, etc
  app.UseMvc();
}
ckr
źródło
1
Zalecam dodanie w ten sposób oprogramowania pośredniego:app.Use<CorsMiddleware>();
Albert221
Możesz zastąpić te 2 ligne: context.Response.StatusCode = (int) HttpStatusCode.OK; czekają na kontekst.Response.WriteAsync (string.Empty); z prostym: powrót;
Hayha,
1
Aby rozwinąć rozwinięcie odpowiedzi @ user8266077: Uwaga: jeśli żądanie z innego powodu nie powiedzie się, to oprogramowanie pośrednie zgłosi wyjątek i nagłówki nie zostaną ustawione. Oznacza to, że w interfejsie nadal będzie wyglądać na problem CORS, nawet jeśli jest to coś zupełnie innego. Ominąłem to, wychwytując wyjątki await _next(context)i ustawiając kod statusu i odpowiedź ręcznie, jeśli tak się stanie. Musiałem także dodać „autoryzację” do kontroli dostępu-Zezwól na nagłówki, aby żądanie inspekcji wstępnej działało podczas wysyłania żądań reakcji wymagających autoryzacji.
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();
    }
Geneza Mo D.
źródło
.SetIsOriginAllowed ((host) => true) rozwiązał to dla mnie.
JensB
wow, więc w pełni spodziewałem się, że każda z pozostałych odpowiedzi zadziała przed tym małym z zaledwie 3 głosami. ale skrupulatnie wypróbowałem każdą z nich ... pod wpływem kaprysu poszedłem po ciebie i zadziałało. dziękuję
roberto tomás
Ten działał dla mnie na .NET Core 3.1, pozwalając na prawie wszystko.
JustinHui
10

Walczyłem z tym przez DAYS.

I w końcu go do pracy, przenosząc app.UseCors(CORS_POLICY);się do TOP dnia Configure().

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

Upewnij się, że zadeklarowałeś funkcjonalność CORS przed> MVC, ponieważ nagłówki muszą zostać zastosowane, zanim MVC zakończy żądanie.

<= Mimo że moja aplikacja nie dzwoniła UseMVC(), przejście UseCors()na górę rozwiązało problem

Również:

  • Microsoft.AspNetCore.Corsbył wymagany pakiet NuGet w .Net Core 2 i niższych; jest teraz automatycznie częścią Microsoft.AspNetCore w .Net Core 3 i wyższych.
  • builder.AllowAnyOrigin() i .AllowCredentials() opcje CORS są teraz wzajemnie wykluczające się w .Net Core 3 i wyższych
  • Wydaje się, że polityka CORS wymaga połączenia kątowego z serwerem https. Adres URL http wydawał się dawać błąd CORS niezależnie od konfiguracji CORS serwera .Net Core. Na przykład http://localhost:52774/api/Contactsdałby błąd CORS; po prostu zmieniając adres URL na https://localhost:44333/api/Contactsdziałający.

Uwaga dodatkowa :

W moim przypadku CORS nie działałby, dopóki nie przeprowadzę się app.UseCors()wyżej app.UseEndpoints(endpoints => endpoints.MapControllers()).

Mglisty dzień
źródło
2
To powinno być odpowiedzią, jeśli używasz Net Core 3. Dziękujemy za uratowanie mi życia!
Kanada Wan
2
„W przypadku routingu punktu końcowego oprogramowanie pośrednie CORS musi być skonfigurowane do wykonywania połączeń między UseRouting i UseEndpoints. Niepoprawna konfiguracja spowoduje, że oprogramowanie pośrednie przestanie działać poprawnie.” tutaj docs.microsoft.com/en-us/aspnet/core/security/…
Mark Schultheiss
„W przypadku routingu punktu końcowego oprogramowanie pośrednie CORS musi być skonfigurowane do wykonywania połączeń między UseRouting i UseEndpoints. Niepoprawna konfiguracja spowoduje, że oprogramowanie pośrednie przestanie działać poprawnie.” tutaj docs.microsoft.com/en-us/aspnet/core/security/…
Mark Schultheiss
7

Żadna z powyższych procedur nie pomogła, a następnie przeczytałem artykuł, który rozwiązał problem.

Poniżej znajduje się kod.

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

i

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

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

i na szczycie mojej metody działania

[EnableCors("CorsPolicy")]
Sainath
źródło
2
To prawdopodobnie zły pomysł: nie należy mieszać oprogramowania pośredniego ( app.UseCors()) [EnableCors()]w tej samej aplikacji. Powinieneś użyć jednego lub drugiego - ale nie obu: docs.microsoft.com/en-us/aspnet/core/security/… :Use the [EnableCors] attribute or middleware, not both in the same app.
FoggyDay
4

spróbuj dodać jQuery.support.cors = true;przed wywołaniem Ajax

Może się również zdarzyć, że dane wysyłane do interfejsu API będą nieporadne,

spróbuj dodać następującą funkcję 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;
    };

następnie w twoich danych: obiekt zmień na

    data: JSON.stringify({
        username: username,
        password: password
    }),
Riaan Saayman
źródło
Dzięki za pomoc. Zdecydowanie wykorzystałem część odpowiedzi, aby znaleźć rozwiązanie na końcu po połączeniu odpowiedzi wszystkich
killerrin
4

Najprostszym rozwiązaniem jest dodanie

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

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

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

do Startup.cs.

amilamad
źródło
3

Myślę, że jeśli używasz własnego oprogramowania pośredniego CORS , musisz upewnić się, że to naprawdę żądanie CORS , sprawdzając nagłówek źródła .

 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
źródło
Dziękuję Ci bardzo. Prawie oszalałem, zadając sobie pytanie, dlaczego Access-Control-Allow-Originnagłówek nie został wydany przez serwer. Właściwie wysłałem żądania za pośrednictwem listonosza bez Originnagłówka. To uratowało mi dzień! (A przynajmniej moje przedpołudnie;))
Paul Kertscher
2

W oparciu o Twój komentarz w odpowiedzi MindingData, nie ma to nic wspólnego z twoimi CORS, działa dobrze.

Działanie kontrolera zwraca nieprawidłowe dane. HttpCode 415 oznacza „Nieobsługiwany typ nośnika”. Dzieje się tak, gdy albo przekażesz niewłaściwy format do kontrolera (tj. XML do kontrolera, który akceptuje tylko json) lub gdy zwrócisz niewłaściwy typ (zwróć Xml w kontrolerze, który zadeklarował, że zwraca tylko xml).

Na później sprawdź jedno z [Produces("...")]atrybutów twojej akcji

Tseng
źródło
Dzięki za pomoc. Wypróbowałem nowe rozwiązanie i bawiłem się wysyłaniem Jsona, który zadziałał po tym, jak go skretyfikowałem i sprawiłem, że zadziałał
killerrin
2

Dla mnie nie miało to nic wspólnego z kodem, którego używałem. W przypadku platformy Azure musieliśmy przejść do ustawień usługi aplikacji, w menu bocznym wpis „CORS”. Tam musiałem dodać domenę, o którą prosiłem. Kiedy już to miałem, wszystko było magiczne.

kjbetz
źródło
2

W launchSettings.json, w iisSettings, ustaw anonymousAuthentication na true:

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

Następnie w Startup.cs, w ConfigureServices, przed services.AddMvc, dodaj:

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

a następnie w metodzie configure przed app. UseMvc () dodaj:

app.UseCors("ApiCorsPolicy");
Adrian
źródło
Zrobiłem to dla mnie, pierwotnie skonfigurowałem mój projekt do uwierzytelniania systemu Windows, ale potem musiałem go zmienić na anonimowy, poprawnie skonfigurowałem CORS, ale to ustawienie w launchSettings.json było winowajcą, dziękuję za opublikowanie tego!
HaRoLD,
2

Używam .Net CORE 3.1 i spędziłem wieki waląc głową w ścianę, gdy zdałem sobie sprawę, że mój kod zaczął działać, ale moje środowisko debugowania zostało zepsute, więc oto 2 wskazówki, jeśli próbujesz rozwiązać problem problem:

  1. Jeśli próbujesz rejestrować nagłówki odpowiedzi przy użyciu oprogramowania pośredniego ASP.NET, nagłówek „Kontrola dostępu - Allow-Origin” nigdy się nie pojawi, nawet jeśli tam jest. Nie wiem jak, ale wydaje się, że jest dodawany poza rurociągiem (w końcu musiałem go użyć wireshark).

  2. .NET CORE nie wyśle ​​w odpowiedzi „Access-Control-Allow-Origin”, chyba że w żądaniu masz nagłówek „Origin”. Listonosz nie ustawi tego automatycznie, więc musisz go dodać samodzielnie.

Andy
źródło
2

W moim przypadku naprawiłem za pomocą UseCors przed UserRouting ..

René Bizelli de Oliveira
źródło
Wpadłem na coś podobnego, kiedy uaktualniłem z dotnet core 2.2 do 3.1. Musiałem przenieść aplikację UseCors () powyżej aplikacji UseRouting (). Ta odpowiedź wskazała mi właściwy kierunek.
Brandonm
1

.NET Core 3.1

Pracował dla mnie i jak mówią doktorzy, aby to zrobić:

w klasie startowej:

readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins"; 

W metodzie ConfigureServices ():

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

W metodzie Configure ():

    app.UseCors(MyAllowSpecificOrigins);  

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

Andrzej
źródło
0

Dostałem odpowiedź MindingData powyżej do pracy, ale musiałem użyć Microsoft.AspNet.Cors zamiast Microsoft.AspNetCore.Cors. Korzystam z projektu interfejsu API aplikacji sieci .NetCore w programie Visual Studio 2019

carl
źródło
2
UWAGA: nie należy używać Microsoft.AspNet.Cors w aplikacji ASP.Net Cor. Jeśli korzystasz z .Net Core 3.0 lub nowszej wersji, nie musisz importować żadnego pakietu NuGet dla CORS. Jeśli korzystasz z platformy .Net Core 2.3 lub nowszej, potrzebujesz odpowiedniej wersji Microsoft.AspNet.Cors firmy NuGet.
FoggyDay
0

The

Microsoft.AspNetCore.Cors

pozwoli ci robić CORS z wbudowanymi funkcjami, ale nie obsługuje żądania OPCJE. Najlepszym jak dotąd obejściem jest utworzenie nowego oprogramowania pośredniego, jak sugerowano w poprzednim poście. Sprawdź odpowiedź oznaczoną jako poprawną w następującym poście:

Włącz nagłówek OPCJE dla CORS w .NET Core Web API

Bonomi
źródło
0

Prosty i łatwy sposób to zrobić.

  1. Zainstaluj pakiet

Install-Package Microsoft.AspNetCore.Cors

  1. Umieść poniższy kod w pliku startup.cs

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

pintu sharma
źródło
0

Oto mój kod:)

  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
źródło
0

Oto jak to zrobiłem.

Widzę, że w niektórych odpowiedziach ustalają app.UserCors("xxxPloicy") i wprowadzają [EnableCors("xxxPloicy")]kontrolery. Nie musisz robić obu.

Oto kroki.

W Startup.cs wewnątrz ConfigureServices dodaj następujący kod.

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

Jeśli chcesz zastosować cały projekt, dodaj następujący kod w Konfiguruj metodę w Startup.cs

app.UseCors("xxxPolicy");

Lub

Jeśli chcesz dodać go do określonych kontrolerów, dodaj kod włączania cors, jak pokazano poniżej.

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

Aby uzyskać więcej informacji: zobacz to

Arshath Shameer
źródło
0

Użyj niestandardowego atrybutu akcji / kontrolera, aby ustawić nagłówki CORS.

Przykład:

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

Następnie kontroler / działanie interfejsu API sieci Web:

[ApiController]
[AllowMyRequests]
public class MyController : ApiController
{
    [HttpGet]
    public ActionResult<string> Get()
    {
        return "Hello World";
    }
}
warrickh
źródło
0

Aby dodać tutaj odpowiedź, jeśli używasz app.UseHttpsRedirection()i nie używasz portu SSL, rozważ skomentowanie tego.

Raj
źródło
0

Używałem blazor webassemble jako klienta i rdzenia interfejsu API asp.net jako backendu i miałem też problem z corsami.

Znalazłem rozwiązanie z tym kodem:

Mój podstawowy interfejs WWW ASP.Net Startup.cs Pierwsze wiersze ConfigureServices i Configure Method wyglądają tak:

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

 //other code below...
}

i moja metoda Konfiguruj:

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

zmień http://example.comw domenie klienta lub adresie IP

Zviadi
źródło
-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
źródło
Zmodyfikuj swoją odpowiedź, aby uwzględnić i wyjaśnić swój kod oraz to, jak różni się on od innych odpowiedzi. To sprawi, że twój post będzie bardziej przydatny i bardziej prawdopodobny, aby został oceniony :)
Das_Geek