Blazor中Microsoft.AspNetCore.Identity的UserManager与RoleManager始终为空
问题根因
- 你在
TransformClaims方法中仅声明了_rolemanager和_userManager两个变量,没有做任何初始化/注入赋值,自然为null值,直接调用方法必然触发空引用异常。 - 你自定义的
AddRolesClaimsTransformation实现了IClaimsTransformation接口,但没有在ConfigureServices中注册,框架不会自动触发该类的TransformAsync方法,这就是你标注「Code Never Hit」的原因。 - 依赖注入配置存在类型不匹配问题:调用
AddIdentity注册的是CustomUserContext类型的用户标识,但后面手动注册的是UserManager<USAIDUserContext>,两者类型不一致,后续要使用UserManager<CustomUserContext>时DI容器找不到对应实现。 - 没必要手动注册
ApplicationDbContext和UserManager,AddIdentity和AddDbContext已经完成了对应服务的注册,手动重复注册反而可能导致生命周期冲突。
修复步骤
步骤1:注册自定义Claims转换服务
在ConfigureServices方法中添加一行注册代码,放在AddAuthorizationCore之后即可:
services.AddScoped<IClaimsTransformation, AddRolesClaimsTransformation>();
注册后框架会在身份验证完成后自动调用TransformAsync方法,不需要你在OnTokenValidated事件里手写转换逻辑。
步骤2:修正UserService和DI注册
首先实现IUserService,注入正确的UserManager<CustomUserContext>来查询用户和角色信息,示例实现如下:
public class UserService : IUserService { private readonly UserManager<CustomUserContext> _userManager; public UserService(UserManager<CustomUserContext> userManager) { _userManager = userManager; } public async Task<CustomUserContext> GetAsync(string email) { return await _userManager.FindByEmailAsync(email); } // 扩展方法获取用户角色 public async Task<IList<string>> GetUserRolesAsync(CustomUserContext user) { return await _userManager.GetRolesAsync(user); } }
然后在ConfigureServices中注册IUserService:
services.AddScoped<IUserService, UserService>();
同时删除原来的两行冗余注册代码:
// 移除这两行 services.AddTransient<UserManager<USAIDUserContext>>(); services.AddTransient<ApplicationDbContext>();
步骤3:完善Claims转换逻辑
在AddRolesClaimsTransformation.TransformAsync方法中补充角色添加逻辑,把数据库中存储的用户角色添加到Claims里:
public async Task<ClaimsPrincipal> TransformAsync(ClaimsPrincipal principal) { var clone = principal.Clone(); var newIdentity = (ClaimsIdentity)clone.Identity; // 取邮箱作为查询条件,和原有逻辑对齐 var emailClaim = principal.Claims.FirstOrDefault(c => c.Type == "email"); if (emailClaim == null || string.IsNullOrEmpty(emailClaim.Value)) { return principal; } // 获取用户信息 var user = await _userService.GetAsync(emailClaim.Value); if (user == null) { return principal; } // 获取用户角色,添加到Claims var roles = await _userService.GetUserRolesAsync(user); foreach (var role in roles) { newIdentity.AddClaim(new Claim(ClaimTypes.Role, role)); } return clone; }
步骤4:删除冗余逻辑
删掉ConfigureSSO里OnTokenValidated事件中调用TransformClaims的相关代码,也删掉原有的手写TransformClaims方法,这部分逻辑已经由注册的IClaimsTransformation自动处理。
内容的提问来源于stack exchange,提问作者jason
相关产品推荐
相关产品推荐

