Как включить CORS в ASP.net Core WebAPI

190

Что я пытаюсь сделать

У меня есть внутренний веб-API ASP.Net Core, размещенный на бесплатном плане Azure (исходный код: https://github.com/killerrin/Portfolio-Backend ).

У меня также есть клиентский веб-сайт, который я хочу заставить использовать этот API. Клиентское приложение не будет размещаться в Azure, а будет размещено на страницах Github или в другой службе веб-хостинга, к которой у меня есть доступ. Из-за этого доменные имена не будут выстраиваться.

Глядя на это, мне нужно включить CORS на стороне Web API, однако я уже несколько часов пробовал все, и он отказывается работать.

Как у меня есть установка клиента Это просто простой клиент, написанный на React.js. Я вызываю API через AJAX в Jquery. Сайт React работает, поэтому я знаю, что это не так. Вызов API Jquery работает, как я подтвердил в Попытке 1. Вот как я делаю вызовы

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

Что я пробовал


Попытка 1 - «правильный» путь

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

Я следовал этому руководству на веб-сайте Microsoft до T, пробуя все 3 варианта включения его в глобальном масштабе в Startup.cs, настраивая его на каждом контроллере и пробуя на каждом действии.

Следуя этому методу, кросс-домен работает, но только на одном действии на одном контроллере (POST для AccountController). Для всего остального Microsoft.AspNetCore.Corsпромежуточное ПО отказывается устанавливать заголовки.

Я установил Microsoft.AspNetCore.Corsчерез NUGET и версия1.1.2

Вот как у меня это настроено в 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();

        ...
        ...
        ...
    }

Как видите, я делаю все как было сказано. Я добавляю Cors перед MVC оба раза, и когда это не сработало, я попытался поставить [EnableCors("MyPolicy")]каждый контроллер так

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

Попытка 2 - грубое принуждение

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

После нескольких часов попыток с предыдущей попыткой я решил, что я попытаюсь перебить его, пытаясь установить заголовки вручную, заставляя их запускаться при каждом ответе. Я сделал это после этого урока о том, как вручную добавлять заголовки к каждому ответу.

Это заголовки, которые я добавил

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

Это другие заголовки, которые я пробовал.

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

С помощью этого метода, кросс-сайт заголовки применяются правильно, и они отображаются в моей консоли разработчика и в Postman. Проблема, однако, заключается в том, что в то время как он проходит Access-Control-Allow-Originпроверку, веб-браузер с шипением подходит (я полагаю), Access-Control-Allow-Headersзаявляя415 (Unsupported Media Type)

Так что метод грубой силы тоже не работает


в заключение

Кто-нибудь заставил это сработать и мог бы протянуть руку или просто указать мне правильное направление?


РЕДАКТИРОВАТЬ

Таким образом, чтобы выполнить вызовы API, мне пришлось прекратить использовать JQuery и переключиться на XMLHttpRequestформат Pure Javascript .

Попытка 1

Мне удалось получить Microsoft.AspNetCore.Corsна работу, следуя ответ MindingData, за исключением в Configureметоде поставив app.UseCorsперед тем app.UseMvc.

Кроме того, в сочетании с Javascript API Solution options.AllowAnyOrigin()поддержка групповых символов также начала работать.

Попытка 2

Таким образом, мне удалось заставить Попытку 2 (грубое принуждение) работать ... с единственным исключением, что Подстановочный знак Access-Control-Allow-Originне работает, и поэтому я должен вручную установить домены, которые имеют к нему доступ.

Это явно не идеально, так как я просто хочу, чтобы этот WebAPI был широко открыт для всех, но, по крайней мере, он работает для меня на отдельном сайте, что означает, что это начало

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
источник
2
Для вашей 415 (Unsupported Media Type)проблемы установите Content-Typeзаголовок запроса на application/json.
Технеций
5
Спасибо, что потратили время на написание такого описательного вопроса.
user1007074
1
Если вы тестируете с помощью Postman, убедитесь, что для Origin установлено значение * или что-то другое для заголовка запроса, тогда попытка # 1 должна работать. Без этого заголовка Access-Control-Allow-Origin не будет возвращен в заголовке ответа.
tala9999

Ответы:

240

Поскольку у вас очень простая политика CORS (разрешить все запросы из домена XXX), вам не нужно усложнять ее. Сначала попробуйте выполнить следующее (очень простая реализация CORS).

Если вы еще этого не сделали, установите пакет CORS nuget.

Install-Package Microsoft.AspNetCore.Cors

В методе ConfigureServices вашего startup.cs добавьте службы CORS.

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

Затем в вашем методе Configure вашего startup.cs добавьте следующее:

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

Теперь попробуй. Политики предназначены для случаев, когда вам нужны разные политики для разных действий (например, разные хосты или разные заголовки). Для вашего простого примера вам это действительно не нужно. Начните с этого простого примера и настройте его по мере необходимости.

Дополнительное чтение: http://dotnetcoretutorials.com/2017/01/03/enabling-cors-asp-net-core/

MindingData
источник
3
XMLHttpRequest не может загрузить andrewgodfroyportfolioapi.azurewebsites.net/api/Authentication . Ответ на запрос предварительной проверки не проходит проверку контроля доступа: в запрашиваемом ресурсе отсутствует заголовок «Access-Control-Allow-Origin». Поэтому происхождение ' localhost: 3000 ' не разрешено. Ответ имел HTTP-код состояния 415.
killerrin
7
Это вряд ли сработает, когда вы зарегистрируете app.UseCors ПОСЛЕ `` app.UseMvc () `. Промежуточные программы выполняются в порядке их регистрации
Ценг
24
использование app.UseCors перед app.UseMvc в методе Configure, кажется, работает. По какой-то причине последовательность действительно имеет значение.
MrClan
1
Для меня самая большая проблема CORS в 2.0 заключается в том, что он не говорит, что не так, просто молча не устанавливает заголовки CORS. Примечание : не забудьте добавить все необходимые заголовки в политику, иначе произойдет сбой (у меня был тип контента). Также странно для меня то, что промежуточное ПО CORS не тормозит обработку запросов, а просто сообщает в журналах, что происхождение не разрешено, и ... передает запрос дальше (порядок промежуточного ПО был правильным).
Андрей M4n0w4R
2
Я должен был включить, options.DisableHttpsRequirement();чтобы все это работало. Кажется, с настройками HTTPS Cors не применяются.
Майкл Браун
210
  • В ConfigureServices добавьте services.AddCors(); ДО службы .AddMvc ();

  • Добавьте UseCors в Configure

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

Главное, что добавить app.UseCors, раньше app.UseMvc().

Убедитесь, что вы объявили функциональность CORS перед MVC, чтобы промежуточное программное обеспечение сработало до того, как конвейер MVC получит управление и завершит запрос.

После того, как описанный выше метод работает, вы можете изменить его, настроить конкретный ORIGIN для приема вызовов API и не оставлять свой API открытым для всех

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

    services.AddMvc();
}

В методе configure скажите CORS использовать политику, которую вы только что создали:

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

Я только что нашел эту компактную статью на эту тему - https://dzone.com/articles/cors-in-net-core-net-core-security-part-vi

Джи Ра
источник
1
Это работает для меня. codeproject.com/Articles/1150023/…
hubert17
17
Это действительно должно получить больше голосов в качестве хорошей "отправной точки". По моему опыту более 25 лет программирования всегда приятно знать, как открыть шлюзы, чтобы убедиться, что они действительно «работают», а затем закрывать / защищать вещи по мере необходимости.
Инди-Джонс
4
Просто чтобы упомянуть это, в отличие Configure()от порядка не очень важно здесь, внутриConfigureServices()
B12Toaster
Я использовал ссылку в Далее Читатель, и эти шаги решили эту ошибку. Я не был уверен, где эти изменения должны быть размещены (я думал, API). Ссылка подтвердила, что они должны быть размещены в API. Спасибо за помощь. Я полностью крутил свои колеса с этой ошибкой.
Ричард
1
FYI - спецификация CORS также гласит, что установка источника "*" (все источники) недопустима, если присутствует заголовок Access-Control-Allow-Credentials. Значение вы не можете использовать AllowCredentials()с , AllowAnyOrigin()как и выше. Для использования AllowCredentials()нужно установить WithOrigins(). docs.microsoft.com/en-us/aspnet/core/security/…
Ник Де Бир
28

Я создал свой собственный класс промежуточного программного обеспечения, который работал для меня, я думаю, что-то не так с классом промежуточного программного обеспечения .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>();
    }
}

и использовал это таким образом в startup.cs

app.UseCorsMiddleware();
user8266077
источник
Очень элегантный способ запуска Access-Control-Allow-Origin.
Артур
Это работает на WebAPI и MVC и не имеет зависимостей, спасибо!
Джо
Я тоже скептически относился к этому, но у меня это сработало. В основном я пытался использовать любой другой метод для достижения этой цели, который я мог найти в Интернете, но независимо от того, что сервер не отвечал заголовками доступа. Это сработало отлично. Я бегу aspnetcore 2.1.
Иордания
Вы должны возвращать заголовки cors, только если клиент отправляет заголовок «Origin» в запросе. В оригинальном CospMiddleware это выглядит так:if (!context.Request.Headers.ContainsKey(CorsConstants.Origin)) return this._next(context);
Андрей Пригоршнев,
2
Может быть, "что-то не так с классом промежуточного программного обеспечения ядра .net", потому что вы просто не добавляете заголовок "Origin" при тестировании с помощью curl или чего-то подобного. Браузеры добавляют этот заголовок автоматически, когда вы делаете запрос в коде js.
Андрей Пригоршнев
18

В моем случае только getзапрос работает хорошо в соответствии с ответом MindingData. Для других типов запросов вам необходимо написать:

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

Не забудьте добавить .AllowAnyHeader()

Towhid
источник
Согласитесь с Towhid, что AllowAnyHeader () необходим. Это позволяет серверу получать запрос OPTIONS, если в запросе HEADER что-то отсутствует.
Ривон
.AllowAnyHeader () сделал это для меня, у меня были проблемы с предполетным ответом.
Так
11

Для того, чтобы расширить свое присутствие на user8266077 «ы ответа , я обнаружил , что все еще нужен ответ OPTIONS питания для предполетных запросов в .NET 2.1 ядро-превью для моего случая использования:

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

а затем включил промежуточное ПО, как в Startup.cs

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
  app.UseMiddleware(typeof(CorsMiddleware));
  // ... other middleware inclusion such as ErrorHandling, Caching, etc
  app.UseMvc();
}
ЦКР
источник
1
Я рекомендую добавить промежуточное программное обеспечение таким образом:app.Use<CorsMiddleware>();
Albert221
Вы можете заменить эти 2 строки: context.Response.StatusCode = (int) HttpStatusCode.OK; ожидание context.Response.WriteAsync (string.Empty); с простым: возврат;
Hayha
1
Чтобы расширить ваше расширение ответа @ user8266077: Остерегайтесь того, что если запрос по какой-либо другой причине не будет выполнен, это промежуточное ПО выдаст исключение и заголовки не будут установлены. Это означает, что в веб-интерфейсе это все равно будет выглядеть как проблема CORS, даже если это что-то совершенно другое. Я обошел это, перехватив все исключения await _next(context)и установив код состояния и ответ вручную, если это произойдет. Мне также пришлось добавить «авторизацию» в Access-Control-Allow-Headers, чтобы предполетный запрос работал при отправке запросов от реакции, требующей авторизации.
Адам
11
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {      
       app.UseCors(builder => builder
                .AllowAnyHeader()
                .AllowAnyMethod()
                .SetIsOriginAllowed((host) => true)
                .AllowCredentials()
            );
    }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddCors();
    }
Mo D Genesis
источник
.SetIsOriginAllowed ((host) => true) решил это за меня.
JensB
вау, так что я полностью ожидал, что любой другой ответ сработает до этого малыша, у которого всего 3 голоса. но я тщательно попробовал каждый из них, ... по своей прихоти, я пошел на ваш, и это сработало. спасибо
Роберто Томас
Это тот, который работал для меня на .NET Core 3.1, чтобы позволить практически все.
JustinHui
10

Я боролся с этим в течение ДНЕЙ.

Я , наконец , получил его на работу, двигаясь app.UseCors(CORS_POLICY);в ТОП из Configure().

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

Убедитесь, что вы объявили функциональность CORS до> MVC, так как заголовки должны быть применены до того, как MVC завершит запрос.

<= Несмотря на то, что мое приложение не звонило UseMVC(), перемещение UseCors()наверх решило проблему

Также:

  • Microsoft.AspNetCore.Corsраньше был обязательным пакетом NuGet в .Net Core 2 и ниже; теперь он автоматически становится частью Microsoft.AspNetCore в .Net Core 3 и выше.
  • builder.AllowAnyOrigin()и .AllowCredentials()параметры CORS теперь взаимоисключающие в .Net Core 3 и выше
  • Политика CORS, кажется, требует Angular вызова сервера с https. URL-адрес http, похоже, выдавал ошибку CORS независимо от конфигурации CORS сервера .Net Core. Например, http://localhost:52774/api/Contactsвыдает ошибку CORS; просто изменив URL на https://localhost:44333/api/Contactsработало.

Дополнительное примечание :

В моем случае CORS не будет работать, пока я не перейду app.UseCors()выше app.UseEndpoints(endpoints => endpoints.MapControllers()).

Туманный день
источник
2
Это должен быть ответ, если вы используете Net Core 3. Спасибо за спасение моей жизни!
Канада будет
2
«При маршрутизации конечной точки промежуточное программное обеспечение CORS должно быть настроено на выполнение между вызовами UseRouting и UseEndpoints. Неправильная конфигурация приведет к тому, что промежуточное программное обеспечение перестанет работать правильно». здесь docs.microsoft.com/en-us/aspnet/core/security/…
Марк
«При маршрутизации конечной точки промежуточное программное обеспечение CORS должно быть настроено на выполнение между вызовами UseRouting и UseEndpoints. Неправильная конфигурация приведет к тому, что промежуточное программное обеспечение перестанет работать правильно». здесь docs.microsoft.com/en-us/aspnet/core/security/…
Марк
7

Ни одна из вышеперечисленных процедур не помогла, и я прочитал статью, в которой решил проблему.

Ниже приведен код.

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

и

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

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

и на вершине моего actionmethod

[EnableCors("CorsPolicy")]
Sainath
источник
2
Вероятно, это плохая идея: вы не должны смешивать middleware ( app.UseCors()) [EnableCors()]в одном приложении. Вы должны использовать один или другой - но не оба: docs.microsoft.com/en-us/aspnet/core/security/… :Use the [EnableCors] attribute or middleware, not both in the same app.
FoggyDay
4

попробуйте добавить jQuery.support.cors = true;перед вызовом Ajax

Также может случиться так, что данные, которые вы отправляете в API, будут ошибочными,

попробуйте добавить следующую функцию 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;
    };

затем в ваших данных: объект изменить его на

    data: JSON.stringify({
        username: username,
        password: password
    }),
Риан Саайман
источник
Спасибо за вашу помощь. Определенно использовал часть ответа, чтобы выяснить решение в конце после объединения всех ответов
killerrin
4

Самое простое решение - добавить

    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
источник
3

Я думаю , что если вы используете свой собственный CORS промежуточными вы должны убедиться , что это действительно Корс запроса, проверяя происхождение заголовка.

 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);
    }
Риддик
источник
Большое спасибо. Я чуть не сошел с ума, спрашивая себя, почему Access-Control-Allow-Originзаголовок не был выдан сервером. На самом деле я отправил запросы через Почтальон без Originзаголовка. Это спасло мой день! (Или, по крайней мере, до полудня;))
Пол Керчер
2

Судя по вашему комментарию в ответе MindingData, он не имеет никакого отношения к вашему CORS, он работает нормально.

Ваше действие контроллера возвращает неверные данные. HttpCode 415 означает «Неподдерживаемый тип носителя». Это происходит, когда вы передаете неправильный формат контроллеру (то есть XML - контроллеру, который принимает только json), или когда вы возвращаете неправильный тип (возвращает Xml в контроллере, который объявлен как возвращающий только xml).

Для более поздней проверки проверьте наличие [Produces("...")]атрибута в вашем действии.

Цзэн
источник
Спасибо за вашу помощь. Попробовал новое решение и поиграл с рассылкой json, и это сработало после того, как я его
выполнил
2

Для меня это не имеет ничего общего с кодом, который я использовал. Для Azure нам пришлось зайти в настройки службы приложений, в боковом меню пункт «CORS». Там мне пришлось добавить домен, с которого я запрашивал материал. Как только я это понял, все стало волшебным.

kjbetz
источник
2

В файле launchSettings.json в разделе iisSettings установите для anonymousAuthentication значение true:

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

Затем в Startup.cs в разделе ConfigureServices перед службами. AddMvc добавьте:

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

и затем, в методе configure, перед app.UseMvc () добавьте:

app.UseCors("ApiCorsPolicy");
Адриан
источник
Это сделало это для меня, я изначально настроил свой проект для аутентификации Windows, но затем мне пришлось изменить его на анонимный, у меня был правильно настроен CORS, но этот параметр в launchSettings.json был виновником, спасибо за публикацию этого !.
HaRoLD
2

Я использую .Net CORE 3.1, и я провел целую вечность, стуча головой об стену с этим, когда я понял, что мой код действительно начал работать, но моя среда отладки была нарушена, так что вот два совета, если вы пытаетесь устранить неполадки проблема:

  1. Если вы пытаетесь регистрировать заголовки ответов, используя промежуточное ПО ASP.NET, заголовок «Access-Control-Allow-Origin» никогда не будет отображаться, даже если он там есть. Я не знаю, как, но, кажется, он был добавлен за пределы конвейера (в конце концов мне пришлось использовать wireshark, чтобы увидеть его).

  2. .NET CORE не отправит «Access-Control-Allow-Origin» в ответе, если в вашем запросе нет заголовка «Origin». Почтальон не установит это автоматически, поэтому вам нужно добавить его самостоятельно.

Энди
источник
2

В моем случае я исправил с помощью UseCors перед UserRouting ..

Рене Бизелли де Оливейра
источник
Я столкнулся с чем-то подобным, когда обновил ядро ​​dotnet 2.2 до 3.1. Пришлось переместить app.UseCors () над app.UseRouting (). Этот ответ указал мне правильное направление.
Брэндонм
1

.NET Core 3.1

Работал для меня и как документы говорят, чтобы сделать это:

в классе запуска:

readonly string MyAllowSpecificOrigins = "_myAllowSpecificOrigins"; 

В методе ConfigureServices ():

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

В методе Configure ():

    app.UseCors(MyAllowSpecificOrigins);  

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

Андрей
источник
0

Я получил ответ MindingData выше, чтобы работать, но мне пришлось использовать Microsoft.AspNet.Cors вместо Microsoft.AspNetCore.Cors. Я использую проект API .NetCore Web Application в Visual Studio 2019

деревенщина
источник
2
ПРИМЕЧАНИЕ: вы не должны использовать Microsoft.AspNet.Cors в приложении ASP.Net Cor. Если вы используете .Net Core 3.0 или выше, вам не нужно вообще импортировать какой-либо пакет NuGet для CORS. Если вы используете .Net Core 2.3 или ниже, вам нужна соответствующая версия Microsoft.AspNet.Cors от NuGet.
FoggyDay
0

Microsoft.AspNetCore.Cors

позволит вам делать CORS со встроенными функциями, но он не обрабатывает запрос OPTIONS. Лучший обходной путь - создание нового Middleware, как было предложено в предыдущем посте. Проверьте ответ, помеченный как правильный в следующем сообщении:

Включить заголовок OPTIONS для CORS в .NET Core Web API

Bonomi
источник
0

Простой и легкий способ сделать это.

  1. Установить пакет

Install-Package Microsoft.AspNetCore.Cors

  1. Поместите этот код ниже в файл startup.cs

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

пинту шарма
источник
0

Вот мой код :)

  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
источник
0

Вот как я это сделал.

Я вижу, что в некоторых ответах они устанавливают app.UserCors("xxxPloicy")и устанавливают [EnableCors("xxxPloicy")]контроллеры. Вам не нужно делать оба.

Вот шаги.

В Startup.cs внутри ConfigureServices добавьте следующий код.

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

Если вы хотите применить ко всему проекту, добавьте следующий код в метод Configure в Startup.cs

app.UseCors("xxxPolicy");

Или

Если вы хотите добавить его в определенные контроллеры, добавьте код включения Cors, как показано ниже.

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

Для получения дополнительной информации: см. Это

Аршат Шамер
источник
0

Используйте пользовательский атрибут Action / Controller для установки заголовков CORS.

Пример:

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

Затем в Web API Controller / Action:

[ApiController]
[AllowMyRequests]
public class MyController : ApiController
{
    [HttpGet]
    public ActionResult<string> Get()
    {
        return "Hello World";
    }
}
warrickh
источник
0

Просто добавьте, чтобы ответить здесь, если вы используете app.UseHttpsRedirection(), и вы нажимаете не порт SSL, рассмотрите возможность комментирования этого.

Радж
источник
0

Я использовал blazor webassembly в качестве клиента и ядро ​​web-интерфейса asp.net в качестве бэкэнда, и у меня тоже была проблема cors.

Я нашел решение с этим кодом:

My ASP.Net core web api Startup.cs ConfigureServices и Configure методов первых строк выглядит следующим образом:

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

 //other code below...
}

и мой метод Configure:

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

изменить http://example.comс вашим клиентским доменом или IP-адресом

Zviadi
источник
-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(); ;
                    });
            });
Альбин CS
источник
Пожалуйста, отредактируйте ваш ответ, включив в него и объяснение вашего кода, и как он отличается от других ответов. Это сделает ваш пост более полезным и с большей вероятностью проголосует за него :)
Das_Geek