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

如何在同一.NET Core API中配置Azure AD与非Azure AD双令牌鉴权

.NET Core 多鉴权方案共存实现

原代码启动崩溃的核心原因

代码崩溃本质是鉴权方案名重复注册:AddMicrosoftIdentityWebApi扩展方法默认会使用JwtBearerDefaults.AuthenticationScheme(即常量值"Bearer")作为它的注册方案名,而你此前已经用完全相同的方案名注册了自定义JWT鉴权。ASP.NET Core鉴权框架不允许同名方案重复注册,这种情况会直接在应用启动阶段抛出InvalidOperationException,根本到不了运行阶段。
你之前遇到的“给两个方案分别设置独立名称后[Authorize]不生效”,本质是默认鉴权策略配置不当,不是独立方案命名方式的问题。

正确的服务配置实现

1. 定义全局统一的方案名称常量

避免后续写代码时硬编码字符串写错,造成方案匹配失效:

public static class CustomAuthenticationSchemes
{
    /// <summary>自定义非Azure AD的JWT鉴权方案</summary>
    public const string CustomJwt = "CustomJwt";
    /// <summary>Azure AD托管的JWT鉴权方案</summary>
    public const string AzureAdJwt = "AzureAdJwt";
    /// <summary>多方案路由的中间层策略名</summary>
    private const string MultiSchemeRouter = "MultiAuthRouter";
}

2. 注册双鉴权方案,避免命名冲突

这里用框架自带的AddPolicyScheme做请求级别的方案路由,解决两个JWT方案共存时的默认匹配问题,彻底解决“[Authorize]无参数时不生效”的问题:

services.AddAuthentication(options =>
{
    // 将默认鉴权入口指向路由层,而不是某一个具体的JWT方案
    options.DefaultScheme = CustomAuthenticationSchemes.MultiSchemeRouter;
    options.DefaultChallengeScheme = CustomAuthenticationSchemes.MultiSchemeRouter;
})
// 配置路由层逻辑:根据请求特征自动匹配需要使用的鉴权方案
.AddPolicyScheme(CustomAuthenticationSchemes.MultiSchemeRouter, "多鉴权方案路由", options =>
{
    options.OnSelectedScheme = context =>
    {
        // 路由规则可以根据实际需求灵活定制:
        // 方式1:根据自定义请求头判断来源
        var authSource = context.Request.Headers["X-Auth-Source"].FirstOrDefault();
        // 方式2:也可以直接解析Authorization头里的令牌前缀,不依赖额外请求头
        // var authHeader = context.Request.Headers["Authorization"].FirstOrDefault();
        // var token = authHeader?.Replace("Bearer ", "");

        return authSource switch
        {
            "Custom" => Task.FromResult(CustomAuthenticationSchemes.CustomJwt),
            "AzureAd" => Task.FromResult(CustomAuthenticationSchemes.AzureAdJwt),
            // 兜底规则:未标识来源时默认走Azure AD鉴权
            _ => Task.FromResult(CustomAuthenticationSchemes.AzureAdJwt)
        };
    };
})
// 注册自定义JWT方案,显式指定独立方案名
.AddJwtBearer(CustomAuthenticationSchemes.CustomJwt, options =>
{
    options.TokenValidationParameters = new TokenValidationParameters()
    {
        ValidateAudience = false,
        ValidateIssuer = false,
        ValidateIssuerSigningKey = false,
        ValidateLifetime = true,
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("private_key"))
    };
})
// 注册Azure AD鉴权,显式传入自定义方案名,覆盖默认的"Bearer"命名
.AddMicrosoftIdentityWebApi(
    configuration: this.Configuration.GetSection("AzureAd"),
    bearerScheme: CustomAuthenticationSchemes.AzureAdJwt
);

3. [Authorize]特性的灵活使用

配置完成后不需要修改框架的其他逻辑,直接按场景使用[Authorize]即可:

  • 控制器/接口需要兼容两种令牌都能访问:直接写无参数的[Authorize],框架会通过之前配置的路由层自动匹配对应鉴权逻辑,不会出现之前的401拦截问题。
  • 控制器/接口需要限制只允许某一类令牌访问:在[Authorize]中显式指定对应方案名即可:
    • 仅允许自定义JWT访问:[Authorize(AuthenticationSchemes = CustomAuthenticationSchemes.CustomJwt)]
    • 仅允许Azure AD令牌访问:[Authorize(AuthenticationSchemes = CustomAuthenticationSchemes.AzureAdJwt)]

实操中的常见注意事项

  • 永远不要给两个不同的鉴权逻辑设置相同的方案名:只要同名方案重复注册,应用启动时就会直接抛出异常,不存在运行时再判断的可能。
  • 不要把默认鉴权方案直接绑定到某一个具体的JWT实现:如果把DefaultScheme直接设为CustomJwt,所有不带参数的[Authorize]请求都会走自定义JWT校验,携带Azure AD令牌的请求会被直接拒绝,这就是之前遇到“[Authorize]不生效”的根本原因。
  • 生产环境不要全量关闭JWT校验规则:代码里将Audience、Issuer、SigningKey的校验全部关闭,存在极高的令牌伪造风险,哪怕是自定义JWT,也至少需要校验签名密钥和令牌发行人,不能完全放开校验逻辑。
  • 路由规则可以不依赖额外请求头:如果不想让前端额外传X-Auth-Source请求头,可以在路由层直接解析令牌的Payload段,根据自定义JWT和Azure AD令牌的固有声明差异自动匹配对应方案,用户侧完全无感知。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.28 17:45:04