本系列专栏基于杨中科老师的《ASP.NET Core技术内幕与项目实战》,本人记录梳理的学习笔记,有部分的增补和省略。更全面系统的讲解,请看杨老师的视频课:【.NET教程,.Net Core视频教程,杨中科主讲】。
一、标识框架
1. 概念
ASP.NET Core 标识框架 是官方提供的身份认证与授权一体化解决方案 ,核心采用基于角色的访问控制(RBAC, Role-Based Access Control) 策略,是.NET 生态中实现用户权限管理的标准方案。
框架原生能力:
- 内置用户、角色、用户角色关联、声明(Claims)、令牌等核心数据表结构
- 提供开箱即用的用户管理、角色管理、权限校验接口
- 原生支持第三方外部登录(GitHub、微信、Google 等)、双因素认证(2FA)、密码重置、邮箱验证等企业级功能
- 解耦业务与身份认证逻辑,大幅降低权限系统开发成本
2. 数据持久化特性
标识框架基于 EF Core实现数据库操作,是它最核心的优势之一:
- 无需手动编写 SQL 语句,完全通过 EF Core 完成 CRUD
- 支持几乎所有主流数据库:SQL Server、MySQL、PostgreSQL、SQLite、Oracle 等
- 遵循 EF Core 的迁移机制,数据库结构可平滑升级
3. 使用流程
(1)自定义实体类
框架提供基类 IdentityUser<TKey>(用户)、IdentityRole<TKey>(角色),TKey 为主键类型(常用long/Guid/string)。推荐自定义继承类,扩展业务所需字段(如昵称、手机号、头像):
cs
// 用户实体:继承IdentityUser<long>,主键为long类型
public class User : IdentityUser<long>
{
// 自定义扩展字段
public string NickName { get; set; }
public string Avatar { get; set; }
}
// 角色实体:继承IdentityRole<long>
public class Role : IdentityRole<long>
{
// 可扩展角色描述、权限等级等字段
public string RoleDesc { get; set; }
}
(2)安装核心 NuGet 包
依赖包是框架运行的基础,执行安装命令:
bash
Install-Package Microsoft.AspNetCore.Identity.EntityFrameworkCore
该包整合了 Identity 核心功能与 EF Core 持久化能力。
(3)创建数据库上下文
自定义DbContext继承自 IdentityDbContext,框架会自动配置 Identity 所需的所有数据表映射:
cpp
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
public class IdDbContext : IdentityDbContext<User, Role, long>
{
public IdDbContext(DbContextOptions<IdDbContext> options) : base(options)
{
}
}
泛型参数:User(自定义用户)、Role(自定义角色)、long(主键类型)
(4)核心操作类
无需直接操作DbContext,框架提供强类型管理器,封装了所有用户 / 角色操作:
UserManager<TUser>:用户管理(创建、删除、修改密码、绑定角色等)RoleManager<TRole>:角色管理(创建、删除、校验角色是否存在等)SignInManager<TUser>:登录管理(登录、登出、双因素认证校验等)
(5)核心返回值:IdentityResult 详解
框架中创建用户、创建角色、修改密码 等方法,返回值均为 Task<IdentityResult>,用于统一封装操作结果:
cs
// 类型定义(简化版)
public class IdentityResult
{
// 操作是否成功
public bool Succeeded { get; }
// 错误信息集合(失败时返回具体原因)
public IEnumerable<IdentityError> Errors { get; }
// 静态方法
public static IdentityResult Success(); // 成功
public static IdentityResult Failed(params IdentityError[] errors); // 失败
}
// 错误详情
public class IdentityError
{
public string Code { get; set; } // 错误码
public string Description { get; set; } // 错误描述
}
注意:必须判断Succeeded,失败时返回Errors给前端,便于排查问题。
(6)依赖注入注册
在Program.cs中注册 Identity 服务,配置密码规则、令牌提供器等:
cs
var builder = WebApplication.CreateBuilder(args);
IServiceCollection services = builder.Services;
// 1. 注册数据库上下文
services.AddDbContext<IdDbContext>(opt =>
{
string connStr = builder.Configuration.GetConnectionString("Default");
opt.UseSqlServer(connStr); // 根据数据库替换为UseMySQL/UseNpgsql等
});
// 2. 注册数据保护(用于加密令牌、密码)
services.AddDataProtection();
// 3. 注册Identity核心服务(AddIdentityCore:轻量级配置)
services.AddIdentityCore<User>(options =>
{
// 密码策略配置(根据业务调整)
options.Password.RequireDigit = false; // 不需要数字
options.Password.RequireLowercase = false; // 不需要小写字母
options.Password.RequireNonAlphanumeric = false; // 不需要特殊字符
options.Password.RequireUppercase = false; // 不需要大写字母
options.Password.RequiredLength = 6; // 最小长度6
// 令牌配置(密码重置、邮箱验证)
options.Tokens.PasswordResetTokenProvider = TokenOptions.DefaultEmailProvider;
options.Tokens.EmailConfirmationTokenProvider = TokenOptions.DefaultEmailProvider;
});
// 4. 完善Identity构建:绑定EF Core、角色管理器、用户管理器
var idBuilder = new IdentityBuilder(typeof(User), typeof(Role), services);
idBuilder.AddEntityFrameworkStores<IdDbContext>() // 绑定EF Core持久化
.AddDefaultTokenProviders() // 默认令牌生成器
.AddRoleManager<RoleManager<Role>>() // 注册角色管理器
.AddUserManager<UserManager<User>>(); // 注册用户管理器
(7)数据库迁移
基于 EF Core 迁移命令,自动生成 Identity 全套数据表(用户表、角色表、用户角色关联表等):
bash
# 生成迁移文件
Add-Migration InitIdentity
# 更新到数据库
Update-Database
执行后,数据库会自动创建以下核心表:
- AspNetUsers(用户表)
- AspNetRoles(角色表)
- AspNetUserRoles(用户角色关联表)
- AspNetUserClaims(用户声明表)等
(8)实战:创建角色 + 创建用户 + 绑定角色
通过RoleManager和UserManager完成初始化数据操作:
cs
[ApiController]
[Route("api/[controller]")]
public class AccountController : ControllerBase
{
private readonly RoleManager<Role> _roleManager;
private readonly UserManager<User> _userManager;
// 依赖注入管理器
public AccountController(RoleManager<Role> roleManager, UserManager<User> userManager)
{
_roleManager = roleManager;
_userManager = userManager;
}
/// <summary>
/// 初始化管理员角色和用户
/// </summary>
[HttpPost("InitAdmin")]
public async Task<IActionResult> InitAdmin()
{
// 1. 判断角色是否存在,不存在则创建
bool roleExists = await _roleManager.RoleExistsAsync("admin");
if (!roleExists)
{
Role role = new Role { Name = "admin", RoleDesc = "系统管理员" };
IdentityResult roleResult = await _roleManager.CreateAsync(role);
if (!roleResult.Succeeded)
return BadRequest(roleResult.Errors);
}
// 2. 判断用户是否存在,不存在则创建并绑定角色
User user = await _userManager.FindByNameAsync("yzk");
if (user == null)
{
user = new User
{
UserName = "yzk",
Email = "yangzhongke8@gmail.com",
EmailConfirmed = true, // 邮箱已验证
NickName = "测试管理员"
};
// 创建用户(密码:123456)
IdentityResult userResult = await _userManager.CreateAsync(user, "123456");
if (!userResult.Succeeded)
return BadRequest(userResult.Errors);
// 为用户绑定admin角色
IdentityResult addRoleResult = await _userManager.AddToRoleAsync(user, "admin");
if (!addRoleResult.Succeeded)
return BadRequest(addRoleResult.Errors);
}
return Ok("初始化成功");
}
}
(9)实战:用户登录校验
完整的登录逻辑:校验用户→校验锁定状态→校验密码→重置 / 累加失败次数
cs
/// <summary>
/// 用户登录
/// </summary>
[HttpPost("Login")]
public async Task<IActionResult> Login(LoginRequest req)
{
string userName = req.UserName;
string password = req.Password;
// 1. 根据用户名查询用户
var user = await _userManager.FindByNameAsync(userName);
if (user == null)
return NotFound($"用户名不存在:{userName}");
// 2. 判断用户是否被锁定
if (await _userManager.IsLockedOutAsync(user))
return BadRequest("账号已锁定,请稍后重试");
// 3. 校验密码
bool isPasswordValid = await _userManager.CheckPasswordAsync(user, password);
if (isPasswordValid)
{
// 密码正确:重置登录失败次数
await _userManager.ResetAccessFailedCountAsync(user);
return Ok("登录成功");
}
else
{
// 密码错误:累加失败次数(达到阈值自动锁定)
await _userManager.AccessFailedAsync(user);
return BadRequest("用户名或密码错误");
}
}
// 登录请求参数
public class LoginRequest
{
public string UserName { get; set; }
public string Password { get; set; }
}
4. 扩展:密码重置
流程:
- 根据邮箱查询用户
- 生成一次性密码重置令牌(时效、防篡改)
- 发送令牌至用户(邮件 / 短信)
- 用户凭令牌重置密码
cs
private readonly ILogger<AccountController> _logger;
private readonly UserManager<User> _userManager;
// 构造函数注入ILogger
public AccountController(ILogger<AccountController> logger, UserManager<User> userManager)
{
_logger = logger;
_userManager = userManager;
}
/// <summary>
/// 发送密码重置邮件
/// </summary>
[HttpPost("SendResetPwdEmail")]
public async Task<IActionResult> SendResetPwdEmail(string email)
{
var user = await _userManager.FindByEmailAsync(email);
if (user == null)
return NotFound("邮箱未注册");
// 生成密码重置令牌(核心方法)
string resetToken = await _userManager.GeneratePasswordResetTokenAsync(user);
// 实际业务:将token拼接成链接,通过邮件服务发送给用户
_logger.LogInformation($"向邮箱 {email} 发送重置令牌:{resetToken}");
return Ok("重置邮件已发送,请查收");
}
/// <summary>
/// 重置密码
/// </summary>
[HttpPost("ResetPassword")]
public async Task<IActionResult> ResetPassword(ResetPwdRequest req)
{
var user = await _userManager.FindByEmailAsync(req.Email);
if (user == null)
return NotFound();
// 验证令牌并重置密码(令牌必须和生成时的用户匹配)
IdentityResult result = await _userManager.ResetPasswordAsync(user, req.Token, req.NewPassword);
if (result.Succeeded)
return Ok("密码重置成功");
return BadRequest(result.Errors);
}
// 重置密码请求参数
public class ResetPwdRequest
{
public string Email { get; set; }
public string Token { get; set; }
public string NewPassword { get; set; }
}
二、补充知识
1. AddIdentity vs AddIdentityCore 区别
AddIdentity:完整注册,包含登录、认证、授权全套服务,适合 MVC/Razor PagesAddIdentityCore:轻量级注册,仅核心用户 / 角色管理,适合Web API(前后端分离项目)
2. 适用场景
- 企业后台管理系统的权限控制
- 前后端分离项目的用户认证
- 需要第三方登录、双因素认证的 Web 应用
3. 提升安全措施
- 生产环境启用强密码策略
- 密码重置令牌设置有效期
- 登录失败次数锁定账号
- 敏感操作开启双因素认证(2FA)
- 邮箱 / 手机号验证后开放完整功能
总结
- ASP.NET Core Identity 是RBAC 权限管理的官方标准方案,基于 EF Core 支持多数据库,开箱即用。
- 开发核心:自定义用户 / 角色实体 → 注册服务 → 用
UserManager/RoleManager操作数据。 - 核心返回值
IdentityResult统一处理操作结果,IdentityResult.Succeeded是判断操作是否成功的关键。 - 框架覆盖用户注册、登录、角色管理、密码重置、2FA 等全场景,适合绝大多数.NET Web 项目。