.NET Core UseCors() не добавляет заголовки

Это будет дубликатом Как работает заголовок Access-Control-Allow-Origin?, но метод там также не работает для меня. Я надеюсь, что просто что-то упустил.

Я пытаюсь получить Access-Control-Allow-Origin заголовок в моем ответе от моего.NET Core Web API, к которому я обращаюсь через AJAX.

Я пробовал несколько вещей. Все, если не указано иное, были в Startup.cs файл.

Способ 1

Согласно документации Microsoft:

public void ConfigureServices(IServiceCollection services)
{
    // Add database
    services.AddDbContext<DbContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DbConnection")));

    // Add the ability to use the API with JSON
    services.AddCors();

    // Add framework services.
    services.AddMvc();
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    loggerFactory.AddConsole(Configuration.GetSection("Logging"));
    loggerFactory.AddDebug();

    if (env.IsDevelopment())
    {
        using (var serviceScope = app.ApplicationServices.GetRequiredService<IServiceScopeFactory>().CreateScope())
        {
            serviceScope.ServiceProvider.GetService<DbContext>().Database.Migrate();
            serviceScope.ServiceProvider.GetService<DbContext>().EnsureSeedData();
        }
    }

    app.UseCors(builder => builder.WithOrigins("https://localhost:44306").AllowAnyMethod());

    app.UseJwtBearerAuthentication(new JwtBearerOptions
    {
        Authority = Configuration["Authentication:AzureAd:AADInstance"] + Configuration["Authentication:AzureAd:TenantId"],
        Audience = Configuration["Authentication:AzureAd:Audience"],
    });

    app.UseMvc();
}

Способ 2

public void ConfigureServices(IServiceCollection services)
{
    // ...

    services.AddCors(options => options.AddPolicy("AllowWebApp",
        builder => builder.AllowAnyMethod()
                          .AllowAnyMethod()
                          .AllowAnyOrigin()));
                          //.WithOrigins("https://localhost:44306")));

    // ...
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    // ...

    app.UseCors("AllowWebApp");

    // ...
}

Я также попытался добавить [EnableCors("AllowWebApp")] на контроллере и методе.

От Почтальона я получаю:

кодирование содержимого → gzip
тип контента → текст / обычный текст; кодировка = UTF-8
дата → ср, 25 янв 2017 04:51:48 GMT
сервер → пустельга
статус → 200
варьировать → Принять кодировку
x-powered-by → ASP.NET
x-sourcefiles → =? UTF-8? B? [УДАЛЕНО]

Я также попробовал это в Chrome и получил похожие заголовки.

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

Итак, я что-то упускаю очень очевидное, или это сломалось? В настоящее время я использую версию 1.1.0.


Отредактируйте добавление JS и заглушки контроллера

function getContactPreviews(resultsCallback) {
    var xmlhttp = new XMLHttpRequest();

    xmlhttp.onreadystatechange = () => {
        if (xmlhttp.readyState == XMLHttpRequest.DONE && xmlhttp.status == 200) {
            resultsCallback(JSON.parse(xmlhttp.response));
        }
    }

    xmlhttp.open("GET", "https://localhost:44357/api/User/ContactsPreview", true);
    xmlhttp.setRequestHeader("Authorization", "Bearer " + localStorage.getItem("AuthorizationToken"));
    xmlhttp.send();
}

Заглушка контроллера

[Authorize]
[Route("api/[controller]")]
public class UserController : ApiController
{
    [HttpGet(nameof(ContactsPreview))]
    [EnableCors("AllowWebApp")]
    public IEnumerable<Customer> ContactsPreview()
    {
        // ...
    }
}

8 ответов

Решение

Проблема заключается в том, что при использовании аутентификации Bearer (или любой другой, которую я себе представляю), он добавляет заголовок "Авторизация", и сервер выдаст одобрение только в том случае, если настройка разрешает этот заголовок.

Есть два способа решения проблемы, и ниже приведен единственный необходимый код. Это идет в Configure() метод в Startup.cs в решении веб-API.

Способ 1: разрешить все заголовки

app.UseCors(builder => builder.WithOrigins("https://localhost:44306")
                                .AllowAnyMethod()
                                .AllowAnyHeader());

Способ 2: разрешить определенные заголовки

app.UseCors(builder => builder.WithOrigins("https://localhost:44306")
                              .AllowAnyMethod()
                              .WithHeaders("authorization", "accept", "content-type", "origin"));

Дополнительные заголовки, потому что, согласно документации:

Браузеры не совсем согласуются с тем, как они устанавливают Access-Control-Request-Headers. Если вы установили заголовки на что-либо, кроме "*", вы должны включить как минимум "accept", "content-type" и "origin" плюс любые пользовательские заголовки, которые вы хотите поддерживать.

Заголовок Access-Control-Allow-Origin возвращается, только если:

  1. Запрос включает заголовок "Origin".
  2. Запрашиваемый источник соответствует политике CORS.

Затем сервер возвращает ACAO-заголовок с URL-адресом источника в качестве значения.

Заголовок Origin обычно устанавливается объектом XMLHttpRequest.

Для получения дополнительной информации см. Как работает CORS

В Startup.cs в конце ConfigureServices() Добавь это:

      services.AddCors();

Затем в Configure() вверху добавьте это:

      app.UseCors(x => x.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().WithExposedHeaders("*"));

// alternatively you could use .With... methods to specify your restrictions:
// app.UseCors(x => x.WithOrigins("http://domain1.com").WithMethods("GET","POST").WithHeaders("Authorization").WithExposedHeaders("*"));

Сегодня я потратил часы на эту проблему только для того, чтобы обнаружить это, потому что .Net Core 3 не поддерживает предварительные запросы OPTIONS, если вы используете метод маршрутизации конечных точек RequirePolicy для включения CORS!

В официальной документации это упоминается, но это не было вызвано явным предупреждением, поэтому я полностью его пропустил.

Следующее устранит проблему, но применит глобальную политику CORS, поэтому будьте осторожны, покупатель!

Конфигурация услуги:

      public void ConfigureServices(IServiceCollection services)
{
    string[] corsOrigins = Configuration.GetSection("AllowedHosts").Get<string[]>();

    services.AddCors(options =>
    {
        options.AddPolicy("AllowConfiguredOrigins", builder => builder
            .WithOrigins(corsOrigins)
            .AllowAnyHeader()
            .AllowAnyMethod()
            .AllowCredentials()
        );
    });
...

В принципе, не делайте этого:

      public static void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseRouting();
    app.UseCors();    
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers().RequireCors("AllowConfiguredOrigins");
    });
...

... сделай это вместо этого

Настроить ()

      public static void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseRouting();
    app.UseCors("AllowConfiguredOrigins");
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers();
    });
...

По состоянию на 17.03.2009..NET Core версии 2.1:

Это, возможно, сэкономит некоторое время другим бедным людям... В какой-то момент я начал разочаровываться и чуть не разочаровался в.NET Core WebApi как отдельном проекте.

В реальных условиях в функциях запуска есть другие конфигурации, например, у меня были Swagger, DI-регистрации и т. Д. Я не мог заставить работать кровавую вещь, пока я не поставил методы AddCors() и UseCors() в качестве первого вызываемого метода. в настройках функций.

 // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors(options =>
            {
                options.AddPolicy("SomePolicy",
                    builder => builder.AllowAnyOrigin()
                        .AllowAnyMethod()
                        .AllowAnyHeader()
                        .AllowCredentials());
            });



 // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            app.UseCors("SomePolicy");

После этого вызовы из приложения Angular 6 (клиентские вызовы Swagger Typescript) начали работать как очарование.

В файле Startup.cs добавьте следующее

public CorsPolicy GenerateCorsPolicy(){
                var corsBuilder = new CorsPolicyBuilder();
                corsBuilder.AllowAnyHeader();
                corsBuilder.AllowAnyMethod();
                corsBuilder.AllowAnyOrigin(); // For anyone access.
                //corsBuilder.WithOrigins("http://localhost:56573"); // for a specific url. Don't add a forward slash on the end!
                corsBuilder.AllowCredentials();
                return corsBuilder.Build();
    }

В методе ConfigureServices:

 services.AddCors(options =>
                {
                    options.AddPolicy("AllowAllOrigins", GenerateCorsPolicy());
                });

// Применять CORS глобально в приложении // В метод Configure добавить

app.UseCors("AllowAllOrigins");  

[DisableCors]
Используя атрибут DisableCors, мы можем отключить CORS для контроллера или действия.

// Включение базы контроллера CORS - если вы применяете глобально, вам это не нужно.

[EnableCors("AllowAllOrigins")]  
public class HomeController: Controller {}  

Я хочу добавить еще одну возможность для тех, кто, возможно, последовал приведенному выше совету, но он все еще не работает. В моем случае я не получал возвращаемый заголовок (или получал его только по первому запросу) из-за порядка регистрации в конвейере.

Я изменил порядок с этого:

app.UseResponseCaching();
app.UseHttpsRedirection();
app.UseCors("WideOpen");
app.UseMvc();

К этому:

app.UseCors("WideOpen");
app.UseResponseCaching();
app.UseHttpsRedirection();
app.UseMvc();

Это решило мою проблему.

              services.AddCors(options => options.AddDefaultPolicy(
            builder => builder
                .SetIsOriginAllowed((x => true))
                .AllowAnyHeader()
                .AllowAnyMethod()));
Другие вопросы по тегам