Identity 框架
大约 2 分钟
Identity 框架
- Authentication 对访问者的用户身份进行验证,“用户是否登录成功”。
- Authorization 验证访问者的用户身份是否有对资源访问的访问权限,“用户是否有权限访问这个地址”。
- Identity 框架采用基于角色的访问控制(Role-Based Access Control,简称RBAC)策略,内置了对用户、角色等表的管理以及相关的接口
- 标识框架使用EF Core对数据库进行操作
使用步骤
安装依赖包:
Microsoft.AspNetCore.Identity.EntityFrameworkCore
编写继承自
IdentityUser<TKey> 、IdentityRole<TKey>
等的自定义类- TKey 代表主键的类型
- 通过继承,可以继续添加框架以外的属性
- 还可以编写实体配置类,方法同普通 EFCore 一样
创建 DBContext 继承自 IdentityDbContext 的类
public class AuthenticationDbContext:IdentityDbContext<User,Role,long> { public AuthenticationDbContext(DbContextOptions<AuthenticationDbContext> options) : base(options) { /* 与分层 EFCore 配置一样,需要提供带参构造,通过主程序注入配置参数 */ } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly); } }
注册 Identity 配置服务
// 为构建 AuthorizationDbContext 上下文提供参数 builder.Services.AddDbContext<AuthenticationDbContext>(opt => { opt.UseSqlServer(connStr); }); // 配置 Identity 参数 builder.Services.AddDataProtection(); builder.Services.AddIdentityCore<User>(options => { options.Password.RequireDigit = false; options.Password.RequireLowercase = false; options.Password.RequireNonAlphanumeric = false; options.Password.RequireUppercase = false; options.Password.RequiredLength = 6; options.Tokens.PasswordResetTokenProvider = TokenOptions.DefaultEmailProvider; options.Tokens.EmailConfirmationTokenProvider = TokenOptions.DefaultEmailProvider; }); // 使用 RoleManager、UserManager 操作数据库 var idBuilder = new IdentityBuilder(typeof(User), typeof(Role), builder.Services); idBuilder.AddEntityFrameworkStores<AuthenticationDbContext>() .AddDefaultTokenProviders().AddRoleManager<RoleManager<Role>>() .AddUserManager<UserManager<User>>();
执行
Add-Migration
、Update-database
迁移在
app.UseAuthorization();
前添加app.UseAuthentication();
启用中间件编写 Controller 测试
示例代码
注入 Manager 进行管理,如果需要手动控制事务需要注入 Context
public UsersController(RoleManager<Role> roleManager, UserManager<User> userManager, AuthenticationDbContext ctx) { this.roleManager = roleManager; this.userManager = userManager; this.ctx = ctx; }
创建 Role
[HttpPost] public async Task<ActionResult> CreateRole(string roleName) { if (!await roleManager.RoleExistsAsync(roleName)) { Role role = new Role() { Name = roleName }; IdentityResult result = await roleManager.CreateAsync(role); if (!result.Succeeded) return BadRequest(result.Errors); } return Ok(); }
创建 User
[HttpPost] public async Task<ActionResult> Regist(RegistRequest msg) { User? user = await userManager.FindByNameAsync(msg.Username); if (user == null) { using var trans = await ctx.Database.BeginTransactionAsync(); user = new User() { UserName = msg.Username}; IdentityResult result1 = await userManager.CreateAsync(user,msg.Password ); IdentityResult result2 = await userManager.AddToRoleAsync(user, msg.Rolename); if (result1.Succeeded && result2.Succeeded) await trans.CommitAsync(); else trans.Rollback(); return result1.Succeeded && result2.Succeeded ? Ok("创建成功") : BadRequest(); } else return BadRequest("用户已存在"); }
登录
[HttpPost] public async Task<ActionResult> Login(LoginRequest msg) { User? user = await userManager.FindByNameAsync(msg.Username); if (user == null) return NotFound($"用户名不存在"); if (await userManager.IsLockedOutAsync(user)) return BadRequest("用户已锁定"); if (await userManager.CheckPasswordAsync(user, msg.Password)) return Ok("登录成功"); _ = await userManager.AccessFailedAsync(user); // 记录登录失败次数 return BadRequest("登录失败"); }
重置密码
[HttpPost] public async Task<ActionResult> PwdReset(string username,string newPassword) { User? user = await userManager.FindByNameAsync(username); if (user == null) return BadRequest("用户不存在"); // 生成 token string token = await userManager.GeneratePasswordResetTokenAsync(user); await Console.Out.WriteLineAsync($"向用户邮箱发送 Token = {token}"); // 用户提供收到的 token 进行密码重置 IdentityResult result = await userManager.ResetPasswordAsync(user, token, newPassword); if (!result.Succeeded) return BadRequest("验证不通过"); return Ok(); }