Как настроить Angular 6 с .NET Core 2, чтобы разрешить CORS с любого хоста? - PullRequest
0 голосов
/ 08 января 2019

У меня есть простое приложение Angular, работающее локально на 4200. Я тестирую веб-API, работающее локально на 5000 с использованием ядра .net. В моем файле startup.cs CORS настроен правильно, чтобы разрешить все, чему я верю.

В разделе ConfigureServices у меня есть: services.AddCors();

В разделе Configure у меня есть:

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

Однако, когда я пытаюсь поразить свой webapi, я все равно получаю это в браузере.

from origin 'http://localhost:4200' заблокировано политикой CORS: Ответ на запрос предварительной проверки не проходит проверку контроля доступа: Перенаправление не разрешено для запроса предварительной проверки.

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

Ответы [ 3 ]

0 голосов
/ 08 января 2019

Регистрация cors в сервисах

services.AddCors(options =>
            {
                options.AddPolicy("CorsPolicy",
                    builder => builder
                    .SetIsOriginAllowed((host) => true)
                    .AllowAnyMethod()
                    .AllowAnyHeader()
                    .AllowCredentials());
            });

добавить связующее ПО Cors

app.UseCors("CorsPolicy");
0 голосов
/ 08 января 2019

Возможные проблемы:

  • В вашем startup.cs.Configure() методе app.UseCors() предшествует app.useMVC()?
  • Содержит ли URL-адрес Http-запроса косую черту (/)?
  • Включает ли запрос Http учетные данные?
  • Получает ли браузер Http-ответ от API?
  • Содержит ли ответ заголовок «Access-Control-Allow-Origin»?
  • Когда вы отправляете запрос от Почтальона, включает ли Http-ответ заголовок «Access-Control-Allow-Origin», а также тело, содержащее данные?

Gotchas

Firefox требует, чтобы для вашего API был установлен сертификат для отправки запроса Http с использованием протокола HTTPS.

Проверьте ваш API с помощью Postman и вашего браузера Developer Tool. Обратите внимание на 2 запроса Http. Http 200 является «предполетным», чтобы увидеть, какие варианты CORS доступны.

  • Если ваш API (.NET) выдает HTTP 500 (Internal Server Error), он вернет страницу исключений для разработчика, и почтальон отобразит сообщение “no ‘Access-Control-Allow-Origin’ header is present on the requested resource” - , это неправильно .
  • Фактическая проблема в этом случае заключается в том, что страницу исключений разработчика нельзя вернуть с сервера клиенту (браузеру), работающему в другом источнике.

Я бы хотел с уважением указать следующее:

  • Спецификация CORS гласит, что установка происхождения для '*' (все источники) недопустима, если присутствует заголовок Access-Control-Allow-Credentials.
  • AllowAnyOrigin() не рекомендуется в производственной среде, если вы не хотите, чтобы кто-либо использовал ваш API, и вы не будете вводить учетные данные.
  • Вам не нужно настраивать CORS на уровне контроллера с атрибутом EnableCors при использовании нескольких политик CORS.
  • Настроить несколько политик CORS с ASP.NET Core очень просто ( см. Учебное пособие ниже )

Следующие статьи заслуживают рассмотрения:

ASP.NET Core 2.2 не позволяет разрешать учетные данные с AllowAnyOrigin ()

Включение запросов перекрестного источника (CORS) в ASP.NET Core

ключевых точек (тдр;):

  • CORS Middleware должно предшествовать любым определенным конечным точкам в конфигурации вашего приложения.
  • URL должен быть указан без завершающего слеша (/).
  • Если браузер отправляет учетные данные, но ответ не содержит действительный заголовок Access-Control-Allow-Credentials , браузер не предоставьте ответ приложению, и запрос перекрестного источника завершится неудачей.
  • Спецификация CORS также гласит, что установка начала координат на "*" (все origin) недействителен, если заголовок Access-Control-Allow-Credentials имеет подарок.
  • Если браузер поддерживает CORS, он автоматически устанавливает эти заголовки для запросов из разных источников.
  • Если ответ не включает заголовок Access-Control-Allow-Origin , запрос перекрестного источника завершается неудачей.

Учебное пособие по CORS: (2) Angular Clients + ASP.NET Core

  1. Создание решения Visual Studio

    md c:\s\a
    cd c:\s\a
    c:\s\a>dotnet new sln -n solutionName
    
  2. Создание базового проекта ASP.NET

    c:\s\a>md s
    c:\s\a>cd s
    c:\s\a\s>dotnet new webapi -o api -n api
    
  3. Настройки запуска API и настройка CORS

launchSettings.json

Клон развития профиля в промежуточный профиль

{
"$schema": "http://json.schemastore.org/launchsettings.json",
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iis": {
    "applicationUrl": "http://localhost:myIISApiPortNumber",
    "sslPort": myIISApiSSLPortNumber
},
"iisExpress": {
    "applicationUrl": "http://localhost:myIISExpressApiPortNumber",
    "sslPort": myIISExpressApiSSLPortNumber
}
},
"profiles": {
"Development (IIS Express)": {
    "commandName": "IISExpress",
    "launchBrowser": true,
    "launchUrl": "api/values",
    "environmentVariables": {
    "ASPNETCORE_ENVIRONMENT": "Development"
    }
},
"Staging (IIS Express)": {
    "commandName": "IISExpress",
    "launchBrowser": true,
    "launchUrl": "api/values",
    "applicationUrl": "https://localhost:myIISExpressApiSSLPortNumber;http://localhost:myIISExpressApiPortNumber",
    "environmentVariables": {
    "ASPNETCORE_ENVIRONMENT": "Staging"
    }
},
"Production (IIS)": {
    "commandName": "IIS",
    "launchBrowser": true,
    "launchUrl": "api/values",
    "environmentVariables": {
    "ASPNETCORE_ENVIRONMENT": "Production"
    },
    "applicationUrl": "https:localhost:myIISApiSSLPortNumber;http://localhost:myIISApiPortNumber"
}
}
}

startup.cs

Добавить конфигурацию CORS

public class Startup
{
    public IConfiguration Configuration { get; }

    public IServiceCollection _services { get; private set; }

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        _services = services;
        RegisterCorsPolicies();
        services.AddMvc()
                .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    }

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseCors("DevelopmentCorsPolicy");
            app.UseDeveloperExceptionPage();
        }
        else if (env.IsStaging())
        {
            app.UseCors("StagingCorsPolicy");
        }
        else
        {
            app.UseCors("ProductionCorsPolicy");
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseMvc(); // CORS middleware must precede any defined endpoints
    }

    private void RegisterCorsPolicies()
    {
        string[] localHostOrigins = new string[] {
        "http://localhost:4200", "http://localhost:3200"};

        string[] stagingHostOrigins= new string[] {
        "http://localhost:4200"};

        string[] productionHostOrigins = new string[] {
        "http://yourdomain.net", "http://www.yourdomain.net",
        "https://yourdomain.net", "https://www.yourdomain.net"};

        _services.AddCors(options =>    // CORS middleware must precede any defined endpoints
        {
            options.AddPolicy("DevelopmentCorsPolicy", builder =>
            {
                builder.WithOrigins(localHostOrigins)
                        .AllowAnyHeader().AllowAnyMethod();
            });
            options.AddPolicy("StagingCorsPolicy", builder =>
            {
                builder.WithOrigins(stagingHostOrigins)
                        .AllowAnyHeader().AllowAnyMethod();
            });
            options.AddPolicy("ProductionCorsPolicy", builder =>
            {
                builder.WithOrigins(productionHostOrigins)
                        .AllowAnyHeader().AllowAnyMethod();
            });
        //options.AddPolicy("AllowAllOrigins",
        //    builder =>
        //    {
        // WARNING: ASP.NET Core 2.2 does not permit allowing credentials with AllowAnyOrigin() 
        // cref: https://docs.microsoft.com/en-us/aspnet/core/migration/21-to-22?view=aspnetcore-2.2&tabs=visual-studio
            //        builder.AllowAnyOrigin()
            //               .AllowAnyHeader().AllowAnyMethod();
            //    });
            //options.AddPolicy("AllowSpecificMethods",
            //    builder =>
            //    {
            //        builder.WithOrigins(productionHostOrigins)
            //               .WithMethods("GET", "POST", "HEAD");
            //    });
            //options.AddPolicy("AllowSpecificHeaders",
            //    builder =>
            //    {
            //        builder.WithOrigins(productionHostOrigins)
            //               .WithHeaders("accept", "content-type", "origin", "x-custom-header");
            //    });
            //options.AddPolicy("ExposeResponseHeaders",
            //    builder =>
            //    {
            //        builder.WithOrigins(productionHostOrigins)
            //               .WithExposedHeaders("x-custom-header");
            //    });
            //options.AddPolicy("AllowCredentials",
            // WARNING: ASP.NET Core 2.2 does not permit allowing credentials with AllowAnyOrigin() cref: https://docs.microsoft.com/en-us/aspnet/core/migration/21-to-22?view=aspnetcore-2.2&tabs=visual-studio
            //    builder =>
            //    {
            //        builder.WithOrigins(productionHostOrigins)
            //               .AllowCredentials();
            //    });
            //options.AddPolicy("SetPreflightExpiration",
            //    builder =>
            //    {
            //        builder.WithOrigins(productionHostOrigins)
            //               .SetPreflightMaxAge(TimeSpan.FromSeconds(2520));
            //    });
        });
    }
}
  1. Запуск API отладки с профилем разработки (IIS Express)

Установить точку останова на ValuesController.Get()

  1. Тест API с почтальоном:

    https://localhost:myApiPortNumber/api/values

    • Заголовок и значения Access-Control-Allow-Origin должны быть в ответе
  2. Создание приложения Angular

    c:\s\a\s>ng new Spa1 --routing (will automatically create Spa folder)
    
  3. Запустить приложение Spa1

    c:\s\a\s>cd Spa1
    c:\s\a\s\Spa1>Ng serve
    
  4. Просмотр http://localhost:4200/

    • Spa1 должен запуститься успешно
  5. Реализация COR в Spa1

app.module.ts

  • Импорт HttpClientModule
import { HttpClientModule } from '@angular/common/http';

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    HttpClientModule,
    BrowserModule,
    AppRoutingModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.ts

  • Импорт HttpClient

  • Добавить getValues() метод с запросом CORS

import { Component, OnInit } from '@angular/core';
import { HttpClient } from '@angular/common/http';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})

export class AppComponent implements OnInit {
  title = 'Spa1';
  values: any;
  apiUrl: string = environment.apiUrl;
  valuesUrl = this.apiUrl + "values";

  constructor(private http: HttpClient) { }

  ngOnInit() {
    this.getValues();
  }
  getValues() {
    this.http.get(this.valuesUrl).subscribe(response => {
      this.values = response;
  }, error => {
  console.log(error);
});
}
}

app.component.html

<div style="text-align:center">
  <h1>
    Welcome to {{ title }}!
  </h1>
</div>
<h2>Values</h2>
<p *ngFor="let value of values">
  {{value}}
</p>
<router-outlet></router-outlet>

environment.ts

export const environment = {
  production: false,
  apiUrl: 'https://localhost:myApiPortNumber/api/'
};
  1. Запустить приложение Spa1

    c:\s\a\s\Spa1>Ng serve
    
  2. Просмотр http://localhost:4200/

    • Chrome & Edge: теперь должен успешно выполнять запросы CORs
    • Safari: я не тестировал
    • Firefox: может заблокировать запрос из-за ненадежного сертификата.

Один из способов исправления блока Firefox:

FireFox | Варианты | Конфиденциальность и безопасность | Безопасность | Сертификаты | [Просмотр сертификатов]:

Диспетчер сертификатов | [Добавить исключение]:

   add localhost

Тест CORS

  1. Clone Spa1

    c:\s\a\s>xcopy /s /i Spa1 Spa2
    
  2. Название рефакторинга Spa2

app.component.ts

export class AppComponent implements OnInit {
  title = 'Spa2';
}
  1. Запустить приложение Spa2 на порт 3200

    c:\s\a\s\Spa2>ng serve --port 3200
    
  2. Просмотр http://localhost:3200/

    • Массив значений должен отображаться на веб-странице
  3. Прекратить отладку API с помощью профиля разработки (IIS Express)

  4. Запуск API отладки с Промежуточный профиль (IIS Express)

  5. Просмотр http://localhost:4200/

    • Массив значений должен отображать на веб-странице.
  6. Просмотр http://localhost:3200/

    • Массив значений не должен отображать на веб-странице.
  7. проверка ответа Http с помощью инструментов разработчика:

    • Заголовок и значения Access-Control-Allow-Origin не должны быть в ответе
0 голосов
/ 08 января 2019

Добавьте следующий фрагмент кода в метод ConfigureServices. Отредактируйте это, чтобы разрешить только пользовательские заголовки.

// Add service and create Policy with options
        services.AddCors(options =>
        {
            options.AddPolicy("CorsPolicy",
                builder => builder.AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader()
                .AllowCredentials()
                );
        });

Добавьте следующее в метод Configure

app.UseCors("CorsPolicy");

Добавить атрибут «EnableCors» к контроллеру.

[EnableCors("CorsPolicy")]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...