为Azure Active Directory Web应用登录添加自定义声明
在Azure AD登录的.NET Core 6 Razor Pages中添加自定义声明
方法一:使用ClaimsTransformation(通用方案)
这是.NET认证体系的标准扩展方式,可在用户身份验证流程中(含每次请求或登录时)注入自定义声明。
- 创建实现
IClaimsTransformation的自定义转换类:
public class CustomClaimsTransformer : IClaimsTransformation { private readonly IUserRepository _userRepository; private readonly ILoginClaimRepository _loginClaimRepository; public CustomClaimsTransformer(IUserRepository userRepository, ILoginClaimRepository loginClaimRepository) { _userRepository = userRepository; _loginClaimRepository = loginClaimRepository; } public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal) { // 克隆身份对象,避免修改原始实例 var clonedPrincipal = principal.Clone(); var identity = clonedPrincipal.Identity as ClaimsIdentity; // 从Azure AD返回的声明中获取用户唯一标识(优先用邮箱, fallback到ObjectId) var userId = identity?.FindFirstValue(ClaimTypes.Email) ?? identity?.FindFirstValue("http://schemas.microsoft.com/identity/claims/objectidentifier"); if (string.IsNullOrEmpty(userId)) return clonedPrincipal; // 从SQL数据库查询自定义声明列表 var customClaims = _loginClaimRepository.ClaimList(userId); foreach (var claim in customClaims) { // 避免重复添加相同声明 if (!identity.HasClaim(c => c.Type == claim.Type && c.Value == claim.Value)) { identity.AddClaim(claim); } } return clonedPrincipal; } }
- 在
Program.cs中注册该服务:
builder.Services.AddScoped<IClaimsTransformation, CustomClaimsTransformer>();
方法二:拦截OpenID Connect登录事件(Azure AD专属)
针对Azure AD的OpenID Connect流程,可在令牌验证通过后、生成ClaimsPrincipal前的节点注入声明,仅在用户登录时触发一次。
在Program.cs的Azure AD认证配置中添加事件拦截:
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApp(builder.Configuration.GetSection("AzureAd")) .EnableTokenAcquisitionToCallDownstreamApi() .AddInMemoryTokenCaches(); // 配置OpenID Connect事件 builder.Services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options => { options.Events = new OpenIdConnectEvents { OnTokenValidated = async context => { // 从DI容器获取数据库仓储实例 var userRepository = context.HttpContext.RequestServices.GetRequiredService<IUserRepository>(); var loginClaimRepository = context.HttpContext.RequestServices.GetRequiredService<ILoginClaimRepository>(); // 获取Azure AD用户标识 var userId = context.Principal.FindFirstValue(ClaimTypes.Email) ?? context.Principal.FindFirstValue("http://schemas.microsoft.com/identity/claims/objectidentifier"); if (!string.IsNullOrEmpty(userId)) { var customClaims = loginClaimRepository.ClaimList(userId); var identity = context.Principal.Identity as ClaimsIdentity; foreach (var claim in customClaims) { if (!identity.HasClaim(c => c.Type == claim.Type && c.Value == claim.Value)) { identity.AddClaim(claim); } } } await Task.CompletedTask; } }; });
方案对比
- ClaimsTransformation:每次身份验证时触发(如每次请求需验证身份),适合需动态更新声明的场景。
- OnTokenValidated:仅在用户登录获取新令牌时触发,声明会存入Cookie直到过期,适合声明不频繁变动的场景。
注意事项
- 确保Azure AD返回的用户标识(邮箱/ObjectId)与SQL数据库中的用户记录能对应,作为查询自定义声明的依据。
- 添加声明前需检查是否已存在,避免重复注入。
- 若使用ClaimsTransformation,频繁查询数据库可考虑加入缓存逻辑优化性能。
内容的提问来源于stack exchange,提问作者Ed Sansbury
相关产品推荐
相关产品推荐

