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

.NET Core 3.1 WebAPI(Microsoft.Identity.Web)应用令牌认证异常

解决ADAL迁移MSAL后WebAPI应用令牌验证失败的问题

问题根源

你的令牌验证流程确实存在问题,核心原因是Microsoft.Identity.Web默认的授权策略依赖用户相关声明(如sub、nameidentifier),而应用令牌(Client Credentials流生成)本身没有这些用户身份声明——即使令牌通过了签名、受众等基础验证,后续的RequireAuthenticatedUser策略校验仍会因为缺少用户声明而判定身份无效,导致返回401。

你观察到的现象(OnTokenValidated触发、Principal已验证但后续身份失效),是因为Microsoft.Identity.Web在令牌验证后会执行默认的Claims转换逻辑,自动过滤掉没有用户标识的身份,最终导致授权策略不通过。

正确解决方案

方案1:调整令牌验证参数与事件处理

在配置Microsoft.Identity.Web身份验证时,修改JwtBearer选项,确保应用令牌的身份不会被过滤:

services.AddMicrosoftIdentityWebApiAuthentication(Configuration)
    .ConfigureJwtBearerOptions(options =>
    {
        var originalValidate = options.Events.OnTokenValidated;
        options.Events.OnTokenValidated = async context =>
        {
            // 先执行原有验证逻辑
            await originalValidate(context);
            
            // 针对应用令牌(无sub声明),手动保留身份
            var identity = context.Principal.Identity as ClaimsIdentity;
            if (identity != null && !context.Principal.HasClaim(c => c.Type == "sub"))
            {
                // 标记身份为已认证,避免后续被过滤
                identity.IsAuthenticated = true;
                // 可选:添加自定义声明标识应用身份
                identity.AddClaim(new Claim("token_type", "application"));
            }
        };
    });

方案2:自定义授权策略

创建同时兼容用户令牌和应用令牌的默认授权策略,替代原有RequireAuthenticatedUser的严格校验:

services.AddAuthorization(options =>
{
    options.DefaultPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .RequireAssertion(context =>
        {
            // 允许两种令牌:有sub声明(用户/代表用户令牌),或有azp声明(应用令牌)
            return context.User.HasClaim(c => c.Type == "sub") 
                || context.User.HasClaim(c => c.Type == "azp");
        })
        .Build();
});

方案3:分场景配置授权策略

如果你的API需要区分用户令牌和应用令牌的访问场景,可以分别配置专属策略:

services.AddMicrosoftIdentityWebApiAuthentication(Configuration);

services.AddAuthorization(options =>
{
    // 默认策略:允许用户令牌访问
    options.DefaultPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .RequireClaim("sub")
        .Build();
    
    // 应用专属策略:允许应用令牌访问
    options.AddPolicy("AppOnly", policy =>
        policy.RequireAuthenticatedUser()
              .RequireClaim("azp"));
});

之后在对应控制器/方法上标注:

  • 用户令牌访问:[Authorize]
  • 应用令牌访问:[Authorize(Policy = "AppOnly")]

临时方案生效的原因

你在Startup.cs中添加的特殊代码,本质上是在令牌验证后强制保留了应用令牌的身份信息,跳过了Microsoft.Identity.Web默认的Claims过滤逻辑,所以能临时解决问题,但这种硬编码的方式不够规范。上面的方案都是基于官方框架的扩展点,更符合Microsoft.Identity.Web的设计逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 01:05:28