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

Blazor WASM调用ASP Web API时令牌无效及CORS重定向问题排查

builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd"));
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"))
;

// 默认对所有请求启用授权,包含两种方案以支持网页或API访问
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder(
JwtBearerDefaults.AuthenticationScheme
, OpenIdConnectDefaults.AuthenticationScheme
).RequireAuthenticatedUser().Build();
});

builder.Services.AddControllers();

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

builder.Services.AddRazorPages()
.AddMicrosoftIdentityUI()
;

builder.Services.AddCors(x => x.AddPolicy("policy", new CorsPolicyBuilder().AllowAnyOrigin().AllowAnyHeader().Build()));

...

app.UseCors("policy");

app.UseHttpsRedirection();

app.UseAuthentication();

app.UseAuthorization();

// 开发环境启用Swagger
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}

...

## WASM配置代码
```csharp
builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });

builder.Services.AddHttpClient<APIHttpClient>(x => x.BaseAddress = new Uri("https://localhost:5033"))
    .AddHttpMessageHandler<CorsAndAuthHttpHandler>();
builder.Services.AddTransient<CorsAndAuthHttpHandler>();

builder.Services.Configure<RemoteAuthenticationOptions<MsalProviderOptions>>(
    options =>
    {
        options.ProviderOptions.DefaultAccessTokenScopes.Add("User.Read");
        options.ProviderOptions.DefaultAccessTokenScopes.Add("Mail.Read");
    });

builder.Services.AddScoped<IAuthenticationProvider, GraphAuthenticationProvider>();
builder.Services.AddScoped(sp =>
{
    return new GraphServiceClient(
        new HttpClient(),
        sp.GetRequiredService<IAuthenticationProvider>(),
        "https://graph.microsoft.com/v1.0/");
});

builder.Services.AddMsalAuthentication(x =>
{
    builder.Configuration.Bind("AzureAd", x.ProviderOptions.Authentication);
});

builder.Services.AddAuthorizationCore(options =>
{
    options.FallbackPolicy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
});

...

public class CorsAndAuthHttpHandler : AuthorizationMessageHandler
{
    public CorsAndAuthHttpHandler(Microsoft.AspNetCore.Components.WebAssembly.Authentication.IAccessTokenProvider provider, NavigationManager navigation) : base(provider, navigation)
    {
        ConfigureHandler(new string[] { "https://localhost:5033" });
    }

    protected override HttpResponseMessage Send(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var resp = base.Send(request, cancellationToken);
        if (resp.StatusCode == System.Net.HttpStatusCode.Found)
        { }
        return resp;
    }
}

错误信息

Access to fetch at 'https://login.microsoftonline.com/...'
(redirected from 'https://localhost:5033/WeatherForecast') from origin
'https://localhost:5034' has been blocked by CORS policy:
    No 'Access-Control-Allow-Origin' header is present on the requested resource.
If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

解决方案

1. 修复认证方案注册冲突

连续两次调用AddAuthentication会覆盖默认方案配置,导致OIDC方案未被正确加载。改为一次注册多个认证方案:

builder.Services.AddAuthentication()
    .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd")) // 注册OIDC方案
    .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd")); // 注册JWT方案

授权策略部分保持原代码不变即可。

2. 为WASM添加API专属权限范围

当前WASM请求的令牌只包含Graph的权限范围,没有Web API的专属范围,导致API判定令牌无效。需要添加API的范围:

builder.Services.Configure<RemoteAuthenticationOptions<MsalProviderOptions>>(
    options =>
    {
        options.ProviderOptions.DefaultAccessTokenScopes.Add("User.Read");
        options.ProviderOptions.DefaultAccessTokenScopes.Add("Mail.Read");
        // 替换为你的Web API的Application ID URI+权限范围,格式如api://<API客户端ID>/access_as_user
        options.ProviderOptions.DefaultAccessTokenScopes.Add("api://你的API客户端ID/access_as_user");
    });

同时要在Entra ID控制台中,确保WASM应用已被授予该API的权限。

3. 避免API触发OIDC重定向流程

OIDC的重定向逻辑是为浏览器请求设计的,API调用遇到无效令牌时不应触发重定向。可以通过以下方式解决:

  • 在API的控制器/端点上显式指定使用JWT认证方案:
    [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
    
  • 或者调整授权策略的方案顺序,优先使用JWT:
    options.FallbackPolicy = new AuthorizationPolicyBuilder(
        JwtBearerDefaults.AuthenticationScheme,
        OpenIdConnectDefaults.AuthenticationScheme
    ).RequireAuthenticatedUser().Build();
    

解决令牌无效问题后,重定向不会发生,CORS错误自然消失(CORS错误是重定向到微软登录页导致的,不属于你的API的CORS控制范围)。

4. 清理冗余的Handler代码

CorsAndAuthHttpHandler中重写的Send方法没有实际作用,直接删除该重写方法即可,保持AuthorizationMessageHandler的默认逻辑,它会自动处理令牌附加和401时的令牌刷新。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.25 11:54:56