.NET Core 7 Web API如何同时实现JWT与Azure AD令牌授权?
.NET Core 7 Web API集成JWT与Azure AD令牌授权解决Scheme冲突问题
问题描述
在.NET Core 7 Web API中同时实现JWT令牌与Azure AD令牌授权时,单独使用两种授权方式均正常,但组合后出现scheme already exists bearer错误。原有实现代码如下:
Azure AD实现代码
builder.Services.AddAuthentication(AzureADDefaults.BearerAuthenticationScheme) .AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd")).EnableTokenAcquisitionToCallDownstreamApi() .AddInMemoryTokenCaches();
JWT令牌实现代码
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(jwtBearerOptions => { jwtBearerOptions.TokenValidationParameters = new TokenValidationParameters() { ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = tokenOptions.Issuer, ValidAudience = tokenOptions.Audience, IssuerSigningKey = signingConfigurations.Key, ClockSkew = TimeSpan.Zero }; });
解决方案
错误根源在于Azure AD和JWT默认均使用Bearer作为认证Scheme名称,导致注册时命名冲突。只需为两者指定不同的Scheme名称,再通过策略或直接在接口上指定即可实现共存。
1. 为两种认证方式分配独特Scheme名称
修改注册代码,给Azure AD和JWT分别指定自定义Scheme名称,避免冲突:
// 注册Azure AD认证,使用自定义Scheme名称"AzureAdBearer" builder.Services.AddAuthentication() .AddMicrosoftIdentityWebApi("AzureAdBearer", builder.Configuration.GetSection("AzureAd")) .EnableTokenAcquisitionToCallDownstreamApi() .AddInMemoryTokenCaches(); // 注册JWT认证,使用自定义Scheme名称"JwtBearer" builder.Services.AddJwtBearer("JwtBearer", jwtBearerOptions => { jwtBearerOptions.TokenValidationParameters = new TokenValidationParameters() { ValidateAudience = true, ValidateLifetime = true, ValidateIssuerSigningKey = true, ValidIssuer = tokenOptions.Issuer, ValidAudience = tokenOptions.Audience, IssuerSigningKey = signingConfigurations.Key, ClockSkew = TimeSpan.Zero }; });
2. 配置全局默认认证策略(可选)
若希望API全局支持两种认证方式的自动识别验证,可添加一个PolicyScheme作为默认认证方案,根据令牌特征自动选择对应的Scheme:
// 设置默认认证方案为自定义的多认证策略 builder.Services.AddAuthentication(options => { options.DefaultAuthenticateScheme = "MultiAuthScheme"; options.DefaultChallengeScheme = "MultiAuthScheme"; }) // 注册PolicyScheme,协调两种认证方式 .AddPolicyScheme("MultiAuthScheme", "MultiAuthScheme", options => { options.ForwardDefaultSelector = context => { var authHeader = context.Request.Headers["Authorization"].FirstOrDefault(); if (!string.IsNullOrEmpty(authHeader) && authHeader.StartsWith("Bearer ")) { var token = authHeader.Substring("Bearer ".Length).Trim(); var tokenHandler = new JwtSecurityTokenHandler(); if (tokenHandler.CanReadToken(token)) { var jwtToken = tokenHandler.ReadJwtToken(token); // 根据令牌的issuer判断是否为Azure AD颁发的令牌 if (jwtToken.Issuer.Contains("login.microsoftonline.com")) { return "AzureAdBearer"; } } } // 默认使用JWT认证Scheme return "JwtBearer"; }; });
3. 接口级别指定认证方案(可选)
如果不需要全局默认,也可以在单个控制器或接口上明确允许两种认证Scheme:
[Authorize(AuthenticationSchemes = "AzureAdBearer,JwtBearer")] [ApiController] [Route("api/[controller]")] public class TestController : ControllerBase { // 接口业务逻辑 }
内容的提问来源于stack exchange,提问作者Yogesh Shinde
相关产品推荐
相关产品推荐

