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

Blazor中Microsoft.AspNetCore.Identity的UserManager与RoleManager始终为空

问题根因

  1. 你在TransformClaims方法中仅声明了_rolemanager和_userManager两个变量,没有做任何初始化/注入赋值,自然为null值,直接调用方法必然触发空引用异常。
  2. 你自定义的AddRolesClaimsTransformation实现了IClaimsTransformation接口,但没有在ConfigureServices中注册,框架不会自动触发该类的TransformAsync方法,这就是你标注「Code Never Hit」的原因。
  3. 依赖注入配置存在类型不匹配问题:调用AddIdentity注册的是CustomUserContext类型的用户标识,但后面手动注册的是UserManager<USAIDUserContext>,两者类型不一致,后续要使用UserManager<CustomUserContext>时DI容器找不到对应实现。
  4. 没必要手动注册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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 17:39:00