Angular 8 使用 ASP NET Core 3.1 Web Api 时出现 CORS 策略问题

Posted

技术标签:

【中文标题】Angular 8 使用 ASP NET Core 3.1 Web Api 时出现 CORS 策略问题【英文标题】:CORS policy issue when consuming ASP NET Core 3.1 Web Api by Angular 8 【发布时间】:2021-02-14 22:49:39 【问题描述】:

我在开发 Angular 8、ASP NET Core Web Api Web 应用程序时遇到了 CORS 策略问题。我的 Angular 应用程序在 http://localhost:4200 上运行 为与 Web Api 通信创建了一项服务。如下所示

@Injectable(
  providedIn: 'root'
)
export class AuthenticationService 

  apiUrl: string = "";
 

  constructor(private http: HttpClient) 
 
    this.apiUrl = 'https://localhost:44316';
  

 
  login(Username: any, Password: any)  
    return this.http.post<Observable<ResultItem<AuthenticationResponse>>>(this.apiUrl + "/api/User/Authenticate", Username: Username, Password: Password);
  
 

Services 稍后在组件中调用,但它只是被注入,并与 subscribe 方法一起使用。

 onLogin()  
    this.authenticationService.login(this.loginFormValues.username.value, this.loginFormValues.password.value).subscribe(
       result => ); 
  

Web Api 在 https://localhost:44316/ 上单独运行 从 Angular 调用的方法的终点如下所示:

[ApiController]
[Route("api/[controller]")]
public class UserController : ControllerBase

    private readonly IUserService userService;

    public UserController(IUserService userService)
    
        this.userService = userService;
    


    [HttpPost("Authenticate")]
    public async Task<IActionResult> Authenticate(AuthenticationModel model)
    
        return Ok(await userService.Login(model));
    

我最关心的是我的启动文件。到目前为止,我已经尝试在那里更改 CORS 设置,但没有成功。 Startup.cs 文件的代码如下所示。

快速注释:

ConfigureServices 方法中的两行代码使用了我的一些外部函数,它们的目的是:

AddSubstracture:将所有存储库注册为瞬态并注册 DbContext。

AddApplication:将存储库上一层的服务注册为瞬态

Startup.cs 代码如下

public class Startup

    private IServiceCollection _services;

    public Startup(IConfiguration configuration, IWebHostEnvironment environment)
    
        Configuration = configuration;
        Environment = environment;
        SportFacilityUnitSettings = configuration.Get<SportFacilityUnitSettings>();
    

    public IConfiguration Configuration  get; 
    public IWebHostEnvironment Environment  get; 
    public SportFacilityUnitSettings SportFacilityUnitSettings  get; 

    public void ConfigureServices(IServiceCollection services)
    
         
        services.AddCors();
        services.AddMvc(option => option.EnableEndpointRouting = false);

        services.AddSubstructure(Configuration, Environment, SportFacilityUnitSettings);
        services.AddApplication(); 
        services.AddScoped<IPasswordHasher<User>, PasswordHasher<User>>();

        var appSettingsSection = Configuration.GetSection("AppSettings");
        services.Configure<AppSettings>(appSettingsSection);
         
        var appSettings = appSettingsSection.Get<AppSettings>();
        var key = Encoding.ASCII.GetBytes(appSettings.Secret);

        services.AddAuthentication(x =>
        
            x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
            x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
        )
        .AddJwtBearer(x =>
        
            x.RequireHttpsMetadata = false;
            x.SaveToken = true;
            x.TokenValidationParameters = new TokenValidationParameters
            
                ValidateIssuerSigningKey = true,
                IssuerSigningKey = new SymmetricSecurityKey(key),
                ValidateIssuer = false,
                ValidateAudience = false
            ;
        ); 
        services.AddControllers().AddNewtonsoftJson(options =>
            options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
        );

        services.Configure<AppSettings>(Configuration.GetSection("AppSettings"));
        services.AddHttpContextAccessor();

       
        _services = services;
    

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    
        app.UseCors(
         options => options.SetIsOriginAllowed(x => _ = true).AllowAnyMethod().AllowAnyHeader().AllowCredentials()
     );
        app.UseMvc();
        app.UseHsts();
        app.UseMiddleware<JwtMiddleware>(); 
        app.UseAuthentication();
        app.UseRouting();  
        app.UseHttpsRedirection();  
        app.UseStaticFiles();
        app.UseAuthorization();  
        app.UseEndpoints(endpoints =>
        
            endpoints.MapControllers(); 
        );

    

当我点击用于发送请求的登录按钮时,我在 Web 浏览器控制台中收到以下错误。

从源“http://localhost:4200”访问“https://localhost:44316/api/User/Authenticate”处的 XMLHttpRequest 已被 CORS 策略阻止:无“访问控制允许源”请求的资源上存在标头。

最奇怪的是,当我调试它并在 Api 层设置断点时,调试器命中它,然后它进入服务层并在 Authentication 方法中的某个地方失败。

【问题讨论】:

如果你调试的时候碰到API,那肯定不是CORS问题。 Chrome 往往会显示错误消息,即使是与 CORS 无关的问题。 如何发送不记名令牌以从 Angular 应用程序进行身份验证? @G-Man 你是对的,Cors 错误具有误导性,并且在更新某些身份验证数据时,错误与 .AsNoTracking() 选项有关。感谢您的支持。 【参考方案1】:

转到托管您的应用程序的 IIS 并检查您是否正确设置了以下信息。

#Step 1 : IIS --> HTTP 响应头]

#Step 2 ::在 IIS 下托管的 API 应用程序中设置 4 个字段

#Step 3:如果以上 2 个步骤都不起作用,请确保您按照 msdn 信息为您的应用程序启用 cors https://docs.microsoft.com/en-us/aspnet/core/security/cors?view=aspnetcore-3.1

第 4 步::调查您在 Web API 中使用的标头信息,以及您的 IIS 设置是否允许这样做(如第 1 步所述)

第 5 步::在您的身份验证方法中放置一个断点,以查看失败的位置和原因。您也可以从该错误信息中获得更多线索。

第 6 步:尝试从前端启用 CrossDomain 为 true。

第 7 步:尝试为两个应用程序(调用应用程序和被调用应用程序)启用 https

【讨论】:

以上是关于Angular 8 使用 ASP NET Core 3.1 Web Api 时出现 CORS 策略问题的主要内容,如果未能解决你的问题,请参考以下文章

由于不允许的 MIME 类型(“text/html”),ASP Net Core 内部的 Angular 8 被阻止

asp.net core + angular2 JWT 承载

深入研究 Angular 和 ASP.NET Core 3.0

ASP.Net Core、Angular2 和基于令牌的身份验证

使用 MSAL 保护 ASP.Net Core Web API 和 Angular App

ASP.NET Core Angular 2 Webpack 热模块替换