Blazor客户端.NET Core:如何从OIDC令牌在Server API中获取用户名
Blazor项目API端获取用户名问题
环境配置
客户端(Blazor)配置
builder.Services.AddOidcAuthentication(opt => { opt.ProviderOptions.Authority = "https://x.y.z/oidc"; opt.ProviderOptions.ClientId = "client"; opt.ProviderOptions.DefaultScopes.Add("email"); opt.ProviderOptions.DefaultScopes.Remove("profile"); opt.ProviderOptions.ResponseType = "code"; }); var IHttpServiceClient = builder.Services.AddHttpClient<IBaseHttpService,BaseHttpService>(); builder.Services.AddScoped<CustomAuthorizationMessageHandler>(); IHttpServiceClient.AddHttpMessageHandler<CustomAuthorizationMessageHandler>();
CustomAuthorizationMessageHandler实现:
public class CustomAuthorizationMessageHandler:AuthorizationMessageHandler { public CustomAuthorizationMessageHandler(IAccessTokenProvider provider , NavigationManager nav) :base(provider, nav) { ConfigureHandler(authorizedUrls: new[] { nav.BaseUri }); } }
客户端可正常获取用户名:
username = (await _authenticationStateProvider.GetAuthenticationStateAsync()).User.Identity!.Name!;
服务端API配置
builder.Services .AddAuthentication("Bearer") .AddJwtBearer("Bearer", options => { options.Authority = "https://x.y.z/oidc"; options.TokenValidationParameters.ValidateAudience = false; options.TokenValidationParameters.ValidateIssuer = true; });
问题
在API端点中尝试获取用户名时:
string username = User.Identity.Name; // 为空 string username = User.Claims.Where(p => p.Type == ClaimTypes.NameIdentifier).First().Value; // 包含GUID前缀
前端<AuthorizeView>显示的Claim中存在name字段(值为emi),但该Claim未传递到API端,需要找到正确获取用户名的方法,避免截取GUID前缀的方式。
解决方案
1. 确保Access Token包含name声明
前端<AuthorizeView>展示的是ID Token中的声明,而API接收的是Access Token,两者的声明内容可能不同。需要检查OIDC提供商的配置:
- 确认客户端请求的Scope包含
profile(即使前端移除了profileScope,若API需要该声明,需将其添加回客户端的DefaultScopes,因为Access Token的内容由请求的Scope决定); - 在OIDC提供商后台配置,确保Access Token中包含
name声明(比如IdentityServer中,需确保客户端的AllowedScopes包含profile,且用户的name字段已正确赋值)。
2. 配置JWT Bearer的声明映射
默认ASP.NET Core会将JWT中的name声明映射到ClaimTypes.Name,但如果映射异常,可手动指定:
builder.Services.AddAuthentication("Bearer") .AddJwtBearer("Bearer", options => { options.Authority = "https://x.y.z/oidc"; options.TokenValidationParameters.ValidateAudience = false; options.TokenValidationParameters.ValidateIssuer = true; // 指定Name声明的映射关系 options.TokenValidationParameters.NameClaimType = "name"; // 若需要角色声明,可同时指定 // options.TokenValidationParameters.RoleClaimType = "role"; });
配置后,User.Identity.Name即可直接获取到name声明的值。
3. 验证传递的Token类型
确认CustomAuthorizationMessageHandler传递给API的是Access Token而非ID Token。可在API端点中打印所有Claim,检查是否存在name:
var allClaims = User.Claims.Select(c => $"{c.Type}: {c.Value}").ToList(); // 输出allClaims查看内容
若没有name声明,说明Access Token本身不包含该字段,需回到OIDC提供商调整配置。
4. 调整OIDC提供商的SubjectId配置(可选)
如果希望ClaimTypes.NameIdentifier直接返回用户名而非GUID,可在OIDC提供商(如IdentityServer)中,将用户的SubjectId设置为用户名。但此操作可能影响依赖SubjectId的其他功能,需谨慎评估。
内容的提问来源于stack exchange,提问作者Dorian
相关产品推荐
相关产品推荐

