ASP.NET Core Identity 从入门到实战:常见问题与解决方案

ASP.NET Core Identity 从入门到实战:常见问题与解决方案

本文基于实际项目开发经验,总结了使用 ASP.NET Core Identity 时最常见的几个问题及其解决方案,帮助开发者快速上手并避免踩坑。

前言

在最近的一个项目中,我使用 ASP.NET Core Identity 搭建用户认证和权限管理系统。在这个过程中遇到了不少问题,比如 DbSet 创建失败、SecurityStamp 为 null、IDENTITY_INSERT 错误等。本文将这些问题及解决方案整理出来,希望能帮助到遇到类似问题的开发者。

一、项目背景与技术栈

  • 框架: ASP.NET Core 6.0
  • ORM: Entity Framework Core 6.0
  • 数据库: SQL Server
  • 认证: Identity + JWT
  • 主键类型: long (支持大数据量)

二、核心问题与解决方案

问题 1:Cannot create a DbSet for 'IdentityRole'

错误现象
复制代码
Cannot create a DbSet for 'IdentityRole<long>' because this type is not included in the model for the context.
原因分析

DbContext 虽然继承了 IdentityDbContext,但可能因为以下原因导致问题:

  1. 迁移文件与当前实体配置不一致
  2. 某个地方直接使用了 IdentityRole<long> 而非自定义的 Role
  3. 程序集初始化器中有冲突的 Identity 配置
解决方案

第一步:正确定义实体类

csharp 复制代码
// 用户实体 - 使用 long 作为主键
public class UserInfo : IdentityUser<long>
{
    public string? OpenId { get; set; }
    public string Nickname { get; set; } = string.Empty;
    public string? AvatarUrl { get; set; }
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
    public bool IsDeleted { get; set; } = false;
    // 其他自定义属性...
}

// 角色实体 - 使用 long 作为主键
public class Role : IdentityRole<long>
{
    public string? Description { get; set; }
    public string? Code { get; set; }
    public string? Permissions { get; set; }
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
}

第二步:正确配置 DbContext

csharp 复制代码
public class GuitarDbContext : IdentityDbContext<UserInfo, Role, long>
{
    public GuitarDbContext(DbContextOptions<GuitarDbContext> options) 
        : base(options)
    {
    }

    // 业务实体
    public DbSet<Order> Orders { get; set; }
    public DbSet<Course> Courses { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // ⚠️ 重要:先调用 base,确保 Identity 表被正确配置
        base.OnModelCreating(modelBuilder);

        // 配置自定义属性
        modelBuilder.Entity<Role>(entity =>
        {
            entity.Property(r => r.Description).HasMaxLength(200);
        });

        // 忽略冗余属性
        modelBuilder.Entity<UserInfo>(entity =>
        {
            entity.Ignore(u => u.Role); // 如果 UserInfo 中有 Role 枚举
        });

        // 应用业务实体配置
        modelBuilder.ApplyConfiguration(new OrderConfiguration());
        
        // 全局查询筛选器(软删除)
        modelBuilder.Entity<UserInfo>().HasQueryFilter(e => !e.IsDeleted);
    }
}

第三步:清理并重新生成迁移

bash 复制代码
# 删除 Migrations 文件夹
# 然后重新生成
dotnet ef migrations add InitialIdentity
dotnet ef database update

问题 2:User security stamp cannot be null

错误现象
复制代码
System.InvalidOperationException: User security stamp cannot be null.
原因分析

SecurityStamp 是 Identity 用于安全验证的重要字段,在以下操作时会用到:

  • AddToRoleAsync
  • CheckPasswordAsync
  • ChangePasswordAsync
  • GenerateUserTokenAsync

如果在创建用户时没有设置 SecurityStamp,这些操作就会报错。

解决方案

方案一:在构造函数中自动生成

csharp 复制代码
public class UserInfo : IdentityUser<long>
{
    public UserInfo()
    {
        // 自动生成安全戳
        SecurityStamp = Guid.NewGuid().ToString();
        ConcurrencyStamp = Guid.NewGuid().ToString();
    }
    
    // 其他属性...
}

方案二:在创建用户时手动设置

csharp 复制代码
[HttpPost("CreateUser")]
public async Task<IActionResult> CreateUser([FromBody] CreateUserRequest req)
{
    var user = new UserInfo
    {
        UserName = req.UserName,
        Email = req.Email,
        PhoneNumber = req.PhoneNumber,
        Nickname = req.Nickname,
        // ✅ 关键:设置 SecurityStamp
        SecurityStamp = Guid.NewGuid().ToString(),
        CreatedAt = DateTime.UtcNow
    };

    var result = await userManager.CreateAsync(user, req.Password);
    if (!result.Succeeded)
    {
        return BadRequest(result.Errors);
    }

    // 现在可以安全地添加角色
    await userManager.AddToRoleAsync(user, "Student");
    
    return Ok(new { user.Id, user.UserName });
}

方案三:修复现有用户数据

csharp 复制代码
public async Task FixSecurityStampsAsync()
{
    var users = await userManager.Users
        .Where(u => u.SecurityStamp == null)
        .ToListAsync();
    
    foreach (var user in users)
    {
        user.SecurityStamp = Guid.NewGuid().ToString();
        await userManager.UpdateAsync(user);
    }
}

问题 3:IDENTITY_INSERT 错误

错误现象
复制代码
SqlException: 当 IDENTITY_INSERT 设置为 OFF 时,不能为表 'AspNetUsers' 中的标识列插入显式值。
原因分析

AspNetUsers 表的 Id 列被配置为自增列(Identity),但代码中尝试手动设置 Id 的值。

解决方案

方案一:不要手动设置 Id(推荐)

csharp 复制代码
// ❌ 错误 - 手动设置 Id
var user = new UserInfo
{
    Id = 123456,  // 不要这样做!
    UserName = "test",
    Email = "test@example.com"
};

// ✅ 正确 - 让数据库自动生成
var user = new UserInfo
{
    UserName = "test",
    Email = "test@example.com",
    Nickname = "测试用户"
};
await userManager.CreateAsync(user, password);

方案二:如果确实需要控制 Id

csharp 复制代码
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
    base.OnModelCreating(modelBuilder);
    
    // 配置不使用自增
    modelBuilder.Entity<UserInfo>()
        .Property(u => u.Id)
        .ValueGeneratedNever();
}

三、用户认证与角色管理完整实现

1. 完整的用户创建流程

csharp 复制代码
[HttpPost("Register")]
public async Task<ActionResult> Register([FromForm] RegisterRequest req)
{
    // 1. 验证手机号
    if (!PhoneNumberValidator.VerifyPhoneNumber(req.PhoneNumber))
    {
        return BadRequest("手机号格式不正确");
    }

    // 2. 验证验证码
    if (!await ValidateVerificationCode(req.PhoneNumber, req.VerificationCode))
    {
        return BadRequest("验证码错误");
    }

    // 3. 检查用户是否存在
    var existingUser = await userManager.FindByNameAsync(req.UserName);
    if (existingUser != null)
    {
        return BadRequest("用户名已存在");
    }

    // 4. 检查/创建角色
    if (!await roleManager.RoleExistsAsync(req.RoleName))
    {
        var role = new Role { 
            Name = req.RoleName,
            Code = req.RoleName,
            CreatedAt = DateTime.UtcNow
        };
        await roleManager.CreateAsync(role);
    }

    // 5. 创建用户
    var user = new UserInfo
    {
        UserName = req.UserName,
        PhoneNumber = req.PhoneNumber,
        Email = req.Email,
        Nickname = req.Nickname,
        SecurityStamp = Guid.NewGuid().ToString(),
        EmailConfirmed = true,
        PhoneNumberConfirmed = true,
        CreatedAt = DateTime.UtcNow
    };

    var result = await userManager.CreateAsync(user, req.Password);
    if (!result.Succeeded)
    {
        return BadRequest(result.Errors);
    }

    // 6. 分配角色
    await userManager.AddToRoleAsync(user, req.RoleName);

    // 7. 返回结果
    return Ok(new
    {
        user.Id,
        user.UserName,
        user.PhoneNumber,
        user.Nickname,
        Role = req.RoleName
    });
}

2. 用户登录与角色获取

核心方法:获取用户角色
csharp 复制代码
// 登录时获取角色
var roles = await userManager.GetRolesAsync(user);
完整的登录实现
csharp 复制代码
[HttpPost("Login")]
public async Task<ActionResult> Login([FromForm] LoginRequest req)
{
    // 1. 验证用户
    var user = await userManager.FindByNameAsync(req.UserName);
    if (user == null)
    {
        return BadRequest("用户名不存在");
    }

    // 2. 验证密码
    if (!await userManager.CheckPasswordAsync(user, req.Password))
    {
        return BadRequest("密码错误");
    }

    // 3. 获取用户角色
    var roles = await userManager.GetRolesAsync(user);
    
    // 4. 获取用户权限(基于角色)
    var permissions = await GetPermissionsByRolesAsync(roles);

    // 5. 构建 Claims
    var claims = new List<Claim>
    {
        new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
        new Claim(ClaimTypes.Name, user.UserName),
        new Claim(ClaimTypes.MobilePhone, user.PhoneNumber ?? ""),
        new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
    };

    // 6. 添加角色 Claims
    foreach (var role in roles)
    {
        claims.Add(new Claim(ClaimTypes.Role, role));
    }

    // 7. 添加权限 Claims
    foreach (var permission in permissions)
    {
        claims.Add(new Claim("Permission", permission));
    }

    // 8. 生成 JWT Token
    var token = GenerateJwtToken(claims);

    // 9. 返回登录结果
    return Ok(new LoginResponse
    {
        Token = token,
        ExpiresIn = 7 * 24 * 60 * 60, // 7天(秒)
        User = new UserInfoDto
        {
            Id = user.Id,
            UserName = user.UserName,
            Nickname = user.Nickname,
            PhoneNumber = user.PhoneNumber,
            Email = user.Email
        },
        Roles = roles.ToList(),
        Permissions = permissions.ToList()
    });
}

3. 在 Controller 中获取当前用户角色

方法一:通过 UserManager 获取
csharp 复制代码
[Authorize]
[HttpGet("MyRoles")]
public async Task<IActionResult> GetMyRoles()
{
    // 从 Token 中获取用户 ID
    var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
    if (string.IsNullOrEmpty(userId))
    {
        return Unauthorized();
    }

    var user = await userManager.FindByIdAsync(userId);
    if (user == null)
    {
        return NotFound();
    }

    // 获取用户的角色
    var roles = await userManager.GetRolesAsync(user);
    
    // 获取用户的权限
    var permissions = await GetPermissionsByRolesAsync(roles);

    return Ok(new
    {
        UserId = user.Id,
        UserName = user.UserName,
        Roles = roles,
        Permissions = permissions,
        IsAdmin = roles.Contains("Admin"),
        IsTeacher = roles.Contains("Teacher")
    });
}
方法二:从 HttpContext 中直接获取
csharp 复制代码
[Authorize]
[HttpGet("CurrentUserInfo")]
public IActionResult GetCurrentUserInfo()
{
    // 从 Claims 中直接获取角色
    var roles = User.FindAll(ClaimTypes.Role)
                    .Select(c => c.Value)
                    .ToList();
    
    // 从 Claims 中获取权限
    var permissions = User.FindAll("Permission")
                         .Select(c => c.Value)
                         .ToList();

    var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
    var userName = User.FindFirst(ClaimTypes.Name)?.Value;

    return Ok(new
    {
        UserId = userId,
        UserName = userName,
        Roles = roles,
        Permissions = permissions,
        IsAdmin = roles.Contains("Admin")
    });
}
方法三:使用扩展方法
csharp 复制代码
public static class UserExtensions
{
    public static async Task<IList<string>> GetRolesAsync(
        this UserManager<UserInfo> userManager, 
        ClaimsPrincipal principal)
    {
        var userId = principal.FindFirst(ClaimTypes.NameIdentifier)?.Value;
        if (userId == null) return new List<string>();
        
        var user = await userManager.FindByIdAsync(userId);
        if (user == null) return new List<string>();
        
        return await userManager.GetRolesAsync(user);
    }
}

// 使用
[Authorize]
[HttpGet("MyRoles")]
public async Task<IActionResult> GetMyRoles()
{
    var roles = await userManager.GetRolesAsync(User);
    return Ok(roles);
}

4. 基于角色的权限管理

定义权限常量
csharp 复制代码
public static class Permissions
{
    // 用户管理
    public const string UserCreate = "User.Create";
    public const string UserRead = "User.Read";
    public const string UserUpdate = "User.Update";
    public const string UserDelete = "User.Delete";
    
    // 订单管理
    public const string OrderCreate = "Order.Create";
    public const string OrderRead = "Order.Read";
    public const string OrderUpdate = "Order.Update";
    public const string OrderDelete = "Order.Delete";
    
    // 课程管理
    public const string CourseCreate = "Course.Create";
    public const string CourseRead = "Course.Read";
    public const string CourseUpdate = "Course.Update";
    public const string CourseDelete = "Course.Delete";
}

// 角色权限映射
public static class RolePermissions
{
    private static readonly Dictionary<string, List<string>> _rolePermissions = new()
    {
        ["Admin"] = new List<string>
        {
            Permissions.UserCreate, Permissions.UserRead, Permissions.UserUpdate, Permissions.UserDelete,
            Permissions.OrderCreate, Permissions.OrderRead, Permissions.OrderUpdate, Permissions.OrderDelete,
            Permissions.CourseCreate, Permissions.CourseRead, Permissions.CourseUpdate, Permissions.CourseDelete
        },
        ["Teacher"] = new List<string>
        {
            Permissions.UserRead,
            Permissions.CourseRead,
            Permissions.CourseCreate,
            Permissions.CourseUpdate
        },
        ["Student"] = new List<string>
        {
            Permissions.UserRead,
            Permissions.CourseRead,
            Permissions.OrderRead,
            Permissions.OrderCreate
        }
    };

    public static List<string> GetPermissions(string role)
    {
        return _rolePermissions.TryGetValue(role, out var permissions) 
            ? permissions 
            : new List<string>();
    }
    
    public static async Task<List<string>> GetPermissionsByRolesAsync(IEnumerable<string> roles)
    {
        var permissions = new List<string>();
        foreach (var role in roles)
        {
            permissions.AddRange(GetPermissions(role));
        }
        return permissions.Distinct().ToList();
    }
}

// 使用
private async Task<List<string>> GetPermissionsByRolesAsync(IList<string> roles)
{
    return await RolePermissions.GetPermissionsByRolesAsync(roles);
}

5. 控制器角色权限控制

csharp 复制代码
[ApiController]
[Route("api/[controller]")]
[Authorize] // 所有方法需要登录
public class UserController : ControllerBase
{
    // 1. 单一角色
    [Authorize(Roles = "Admin")]
    [HttpGet("admin-only")]
    public IActionResult AdminOnly()
    {
        return Ok("只有管理员可以访问");
    }

    // 2. 多个角色(或关系)
    [Authorize(Roles = "Admin,Teacher")]
    [HttpGet("staff-only")]
    public IActionResult StaffOnly()
    {
        return Ok("管理员或教师可以访问");
    }

    // 3. 同时拥有多个角色(且关系)
    [Authorize(Roles = "Admin")]
    [Authorize(Roles = "Manager")]
    [HttpGet("admin-manager")]
    public IActionResult AdminAndManager()
    {
        return Ok("同时拥有管理员和管理者角色");
    }

    // 4. 基于策略的权限控制
    [Authorize(Policy = "UserRead")]
    [HttpGet("{id}")]
    public async Task<IActionResult> GetUser(long id)
    {
        return Ok(await userService.GetUserAsync(id));
    }

    [Authorize(Policy = "UserCreate")]
    [HttpPost]
    public async Task<IActionResult> CreateUser([FromBody] CreateUserRequest req)
    {
        return Ok(await userService.CreateUserAsync(req));
    }

    [Authorize(Policy = "UserDelete")]
    [HttpDelete("{id}")]
    public async Task<IActionResult> DeleteUser(long id)
    {
        return Ok(await userService.DeleteUserAsync(id));
    }

    // 5. 动态权限检查
    [HttpGet("check-role")]
    public async Task<IActionResult> CheckRole([FromQuery] string roleName)
    {
        var user = await GetCurrentUserAsync();
        var roles = await userManager.GetRolesAsync(user);
        var hasRole = roles.Contains(roleName);
        
        return Ok(new
        {
            UserName = user.UserName,
            CheckedRole = roleName,
            HasRole = hasRole,
            AllRoles = roles
        });
    }

    // 6. 允许匿名访问(覆盖 Controller 级别)
    [AllowAnonymous]
    [HttpGet("public-info")]
    public IActionResult PublicInfo()
    {
        return Ok("任何人都可以访问");
    }
}

6. 在 Service 层获取当前用户角色

csharp 复制代码
public class UserService
{
    private readonly UserManager<UserInfo> _userManager;
    private readonly IHttpContextAccessor _httpContextAccessor;

    public UserService(
        UserManager<UserInfo> userManager,
        IHttpContextAccessor httpContextAccessor)
    {
        _userManager = userManager;
        _httpContextAccessor = httpContextAccessor;
    }

    private async Task<UserInfo> GetCurrentUserAsync()
    {
        var userId = _httpContextAccessor.HttpContext?.User
            .FindFirst(ClaimTypes.NameIdentifier)?.Value;
            
        if (string.IsNullOrEmpty(userId))
            throw new UnauthorizedAccessException("用户未登录");
            
        var user = await _userManager.FindByIdAsync(userId);
        if (user == null)
            throw new Exception("用户不存在");
            
        return user;
    }

    private async Task<IList<string>> GetCurrentUserRolesAsync()
    {
        var user = await GetCurrentUserAsync();
        return await _userManager.GetRolesAsync(user);
    }

    private async Task<bool> HasRoleAsync(string roleName)
    {
        var roles = await GetCurrentUserRolesAsync();
        return roles.Contains(roleName);
    }

    public async Task<bool> CheckUserPermissionAsync(string permission)
    {
        var user = await GetCurrentUserAsync();
        var roles = await GetCurrentUserRolesAsync();
        var permissions = await RolePermissions.GetPermissionsByRolesAsync(roles);
        return permissions.Contains(permission);
    }
}

四、权限策略配置

1. 在 Program.cs 中配置策略

csharp 复制代码
builder.Services.AddAuthorization(options =>
{
    // 基于角色的策略
    options.AddPolicy("AdminOnly", policy => 
        policy.RequireRole("Admin"));
    
    options.AddPolicy("AdminOrTeacher", policy => 
        policy.RequireRole("Admin", "Teacher"));
    
    // 基于权限的策略
    options.AddPolicy("UserRead", policy => 
        policy.RequireClaim("Permission", Permissions.UserRead));
    
    options.AddPolicy("UserManage", policy => 
        policy.RequireClaim("Permission", Permissions.UserCreate, 
                           Permissions.UserUpdate, Permissions.UserDelete));
    
    options.AddPolicy("OrderFullAccess", policy => 
        policy.RequireClaim("Permission", Permissions.OrderCreate, 
                           Permissions.OrderRead, 
                           Permissions.OrderUpdate, 
                           Permissions.OrderDelete));
    
    // 自定义策略
    options.AddPolicy("SeniorUser", policy => 
        policy.RequireAssertion(context =>
            context.User.IsInRole("Admin") || 
            context.User.HasClaim("MemberLevel", "VIP")
        ));
});

2. 自定义权限特性

csharp 复制代码
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class PermissionAttribute : AuthorizeAttribute
{
    public PermissionAttribute(string permission) : base()
    {
        Policy = permission;
    }
}

// 使用
[Permission(Permissions.UserDelete)]
[HttpDelete("{id}")]
public IActionResult DeleteUser(long id)
{
    return Ok($"删除用户 {id}");
}

五、获取角色的常用场景总结

场景 方法 示例
登录时获取角色 GetRolesAsync(user) var roles = await userManager.GetRolesAsync(user);
Controller 中获取 User.FindAll(ClaimTypes.Role) var roles = User.FindAll(ClaimTypes.Role).Select(c => c.Value);
从 Token 中获取 直接从 Claims 读取 用户登录后角色已在 Token 中
Service 层获取 GetCurrentUserRolesAsync() 通过 UserManager 获取当前用户
检查是否有某个角色 IsInRoleAsync(user, role) await userManager.IsInRoleAsync(user, "Admin")
获取用户所有角色 GetRolesAsync(user) var roles = await userManager.GetRolesAsync(user);

六、常见问题排查清单

问题 检查项 解决方案
DbSet 创建失败 DbContext 是否正确继承 IdentityDbContext<TUser, TRole, TKey> 重新生成迁移
SecurityStamp 为 null 创建用户时是否设置了 SecurityStamp 在构造函数或创建时生成
IDENTITY_INSERT 错误 是否手动设置了 Id 让数据库自动生成 Id
角色获取失败 Token 中是否包含角色 Claims 登录时添加角色 Claims
权限验证失败 策略是否正确注册 检查 Program.cs 中的策略配置
获取角色为空 用户是否已分配角色 检查 AspNetUserRoles

七、最佳实践总结

1. 创建用户时的必做事项

csharp 复制代码
// ✅ 必做清单
var user = new UserInfo
{
    UserName = req.UserName,
    // 1. 设置 SecurityStamp
    SecurityStamp = Guid.NewGuid().ToString(),
    // 2. 设置 ConcurrencyStamp
    ConcurrencyStamp = Guid.NewGuid().ToString(),
    // 3. 不设置 Id(自动生成)
    // 4. 设置其他必填字段
    Email = req.Email,
    PhoneNumber = req.PhoneNumber,
    CreatedAt = DateTime.UtcNow
};

2. 登录时的必做事项

csharp 复制代码
// ✅ 必做清单
// 1. 验证用户
var user = await userManager.FindByNameAsync(req.UserName);

// 2. 验证密码
var isValid = await userManager.CheckPasswordAsync(user, req.Password);

// 3. 获取角色
var roles = await userManager.GetRolesAsync(user);

// 4. 将角色添加到 Claims
foreach (var role in roles)
{
    claims.Add(new Claim(ClaimTypes.Role, role));
}

// 5. 生成 Token
var token = GenerateJwtToken(claims);

3. 权限控制的最佳实践

  • 使用策略(Policy)而非硬编码角色:更灵活、易维护
  • 将权限声明添加到 Token 中:减少数据库查询
  • 使用 [Authorize] 特性保护所有需要认证的端点
  • 使用 [AllowAnonymous] 显式标记公共端点

八、完整代码示例

登录响应 DTO

csharp 复制代码
public class LoginResponse
{
    public string Token { get; set; }
    public long ExpiresIn { get; set; } // 过期时间(秒)
    public UserInfoDto User { get; set; }
    public List<string> Roles { get; set; }
    public List<string> Permissions { get; set; }
}

public class UserInfoDto
{
    public long Id { get; set; }
    public string UserName { get; set; }
    public string Nickname { get; set; }
    public string PhoneNumber { get; set; }
    public string Email { get; set; }
}

完整的用户服务

csharp 复制代码
public interface IUserService
{
    Task<LoginResponse> LoginAsync(LoginRequest request);
    Task<bool> RegisterAsync(RegisterRequest request);
    Task<List<string>> GetUserRolesAsync(long userId);
    Task<bool> HasPermissionAsync(long userId, string permission);
}

public class UserService : IUserService
{
    private readonly UserManager<UserInfo> _userManager;
    private readonly RoleManager<Role> _roleManager;
    private readonly IConfiguration _configuration;

    public UserService(
        UserManager<UserInfo> userManager,
        RoleManager<Role> roleManager,
        IConfiguration configuration)
    {
        _userManager = userManager;
        _roleManager = roleManager;
        _configuration = configuration;
    }

    public async Task<LoginResponse> LoginAsync(LoginRequest request)
    {
        var user = await _userManager.FindByNameAsync(request.UserName);
        if (user == null || !await _userManager.CheckPasswordAsync(user, request.Password))
        {
            throw new Exception("用户名或密码错误");
        }

        var roles = await _userManager.GetRolesAsync(user);
        var permissions = await RolePermissions.GetPermissionsByRolesAsync(roles);
        var claims = BuildClaims(user, roles, permissions);
        var token = GenerateJwtToken(claims);

        return new LoginResponse
        {
            Token = token,
            ExpiresIn = 7 * 24 * 60 * 60,
            User = new UserInfoDto
            {
                Id = user.Id,
                UserName = user.UserName,
                Nickname = user.Nickname,
                PhoneNumber = user.PhoneNumber,
                Email = user.Email
            },
            Roles = roles.ToList(),
            Permissions = permissions
        };
    }

    public async Task<List<string>> GetUserRolesAsync(long userId)
    {
        var user = await _userManager.FindByIdAsync(userId.ToString());
        if (user == null)
        {
            return new List<string>();
        }
        return (await _userManager.GetRolesAsync(user)).ToList();
    }

    public async Task<bool> HasPermissionAsync(long userId, string permission)
    {
        var user = await _userManager.FindByIdAsync(userId.ToString());
        if (user == null) return false;
        
        var roles = await _userManager.GetRolesAsync(user);
        var permissions = await RolePermissions.GetPermissionsByRolesAsync(roles);
        return permissions.Contains(permission);
    }
}

九、参考资料


本文基于 .NET 6 和实际项目经验编写,如有问题欢迎交流讨论。

相关推荐
n8n1 小时前
Spring AI 三层架构详解:ChatModel → ChatClient → Controller,同步调用 vs 流式调用(SSE)
后端
小傅哥1 小时前
Java + DDD,1:1 复刻 Deepseek Harness 项目
前端·后端·ai编程
Lambert2811 小时前
AgentScope Java 从零(03):Agent 的记性默认全开,我在第 50 轮翻了车
后端·aigc
积硅步致千里1 小时前
Word 里的 .wmf 其实是 EMF:一次 metafile 转 PNG 排障
前端·后端
爱读源码的大都督2 小时前
DeepSeek面试官问:生产RAG系统回答不准确,该如何定位和优化?这样回答,能让面试官当场给你Offer!
java·后端·python
杨运交2 小时前
[069][公共模块]Spring Boot 全局异常处理与参数校验实战(下):校验异常精细化处理与 WebFlux 适配
java·spring boot·后端
Andya_net3 小时前
Spring Boot | 条件注解完全指南:从 @Conditional 到 @ConditionalOnExpression 的原理、实践与避坑
spring boot·后端·python
ly76893 小时前
Spring 中的 @Configuration 与 @Component 差异:为何代理时机决定 Bean 生命周期行为
java·后端·spring·注解·代理·bean生命周期
明月_清风3 小时前
字符串匹配四大经典算法:BF、RK、BM、KMP 到底有什么区别?
后端·算法