You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决.NET Core+Azure AD认证API被Angular调用时的CORS错误

解决Angular调用Azure AD认证的.NET Core API时的CORS错误问题

我来帮你分析下这个问题——其实这不是单纯的CORS配置错误,而是认证流程的逻辑冲突导致的。咱们一步步拆解问题,然后给出解决方案:

核心问题分析

你的API配置了全局的RequireAuthenticatedUser授权策略,所以当未登录的请求访问/api/azureauth/me时,ASP.NET Core会自动重定向到Azure AD的登录页面(login.microsoftonline.com)。但Angular是通过AJAX请求调用API的,浏览器不允许AJAX请求跨域重定向到第三方域名(Azure的登录域名不会给你的Angular origin添加CORS响应头),所以直接触发了CORS和CORB错误。

同时你当前的CORS中间件顺序也有问题:app.UseCors放在了app.UseMvc之后,这会导致请求已经被Mvc处理(触发重定向),CORS头根本没机会被添加到响应里。

分步解决方案

1. 调整CORS中间件顺序

在Startup.cs的Configure方法里,把UseCors移到UseAuthentication和UseMvc之前,确保CORS头能被正确添加到所有响应中:

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

    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseCookiePolicy();
    app.UseCors("CorsPolicy"); // 移到这里,确保优先处理CORS
    app.UseAuthentication();
    app.UseMvc();
}

2. 让API针对AJAX请求返回401,而非重定向

修改Cookie认证的行为,当请求是API路径(/api开头)时,返回401 Unauthorized而不是重定向到登录页面。在ConfigureServices里添加Cookie配置:

services.Configure<CookieAuthenticationOptions>(AzureADDefaults.CookieScheme, options =>
{
    options.Events.OnRedirectToLogin = context =>
    {
        // 判断是否为API请求
        if (context.Request.Path.StartsWithSegments("/api"))
        {
            context.Response.StatusCode = StatusCodes.Status401Unauthorized;
            return Task.CompletedTask;
        }
        // 非API请求保持原重定向逻辑(比如浏览器直接访问)
        context.Response.Redirect(context.RedirectUri);
        return Task.CompletedTask;
    };
});

3. 配置API支持Bearer Token认证

因为Angular应该通过Bearer Token(而非Cookie)来调用API,所以需要添加JWT Bearer认证支持,让API同时兼容浏览器Cookie登录和Angular的Token登录:

services.AddAuthentication()
    .AddAzureAD(options => Configuration.Bind("AzureAd", options))
    // 添加JWT Bearer认证
    .AddJwtBearer(options =>
    {
        options.Authority = $"https://login.microsoftonline.com/{Configuration["AzureAd:TenantId"]}/v2.0/";
        options.Audience = Configuration["AzureAd:ClientId"];
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuer = false,
            // 根据你的需求调整其他验证参数
        };
    });

// 更新授权策略,允许两种认证方式
services.AddMvc(options => {
    var policy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .AddAuthenticationSchemes(AzureADDefaults.AuthenticationScheme, JwtBearerDefaults.AuthenticationScheme)
        .Build();
    options.Filters.Add(new AuthorizeFilter(policy));
});

4. 修正Angular端的请求配置

你在Angular请求头里添加的Access-Control-Allow-*是响应头,不需要在客户端请求里设置,反而会干扰请求。同时需要引入Azure AD的MSAL库来获取Token,然后在请求中带上Bearer Token:

第一步:清理请求头

const httpOptions = {
    headers: new HttpHeaders({
        'Content-Type': 'application/json',
        'Accept': 'application/json'
    })
};

第二步:使用MSAL库获取并携带Token

安装@azure/msal-angular,配置Azure AD应用信息,登录后获取Token,然后添加到请求头:

// 登录成功后获取Token(示例代码)
this.msalService.acquireTokenSilent({
  scopes: ['openid', 'profile', `api://${clientId}/access_as_user`]
}).subscribe(tokenResponse => {
  // 给请求头添加Bearer Token
  httpOptions.headers = httpOptions.headers.set('Authorization', `Bearer ${tokenResponse.accessToken}`);
});

// 调用API
public me() {
    return this.http.get(`${this.baseUrl}/me`, httpOptions)
        .pipe(
            map(data => data),
            catchError(err => {
                console.log('请求出错', err);
                // 处理401,比如跳转到登录页面
                if (err.status === 401) {
                    this.msalService.loginRedirect();
                }
                return throwError(() => err);
            })
        );
}

额外注意事项

  • 确保你的Azure AD应用注册中,API应用暴露了正确的范围(Scope),Angular应用添加了对应的API权限并授予管理员同意。
  • 如果你不需要浏览器直接访问API的场景,可以完全移除Cookie认证,只保留Bearer Token认证,进一步简化配置。

内容的提问来源于stack exchange,提问作者Hugo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 08:13:57