中间件:
1、Authentication对访问者的用户身份进行验证,“用户是否登录成功”。
2、Authorization验证访问者的用户身份是否有对资源访问的访问权限,“用户是否有权限访问这个地址”。
简单描述
1、标识(Identity)框架:采用基于角色的访问控制(Role-Based Access Control,简称RBAC)策略,内置了对用户、角色等表的管理以及相关的接口,支持外部登录、2FA等。它允许我们创建、读取、更新和删除账户。支持账号验证、身份验证、授权、恢复密码和SMS双因子身份验证。它还支持微软、Facebook和Google等第三方登录提供商。它提供了一个丰富的API,并且这些API还可以进行大量的扩展。我们将在本书的后面实现这些功能。
2、标识框架使用EF Core对数据库进行操作,因此标识框架支持几乎所有数据库。
使用场景
涉及注册、登录和修改密码等功能,登录系统后,有些功能会提示没有权限,甚至有些位置我们无法访问,这些都是系统权限和认证的体现。
配置Identity
安装Nuget
Microsoft.AspNetCore.Identity.EntityFrameworkCore。 |
创建Identity上下文对象
public class MyContext:IdentityDbContext<User,Role,long> { public MyContext(DbContextOptions<MyContext> options) : base(options) { }
protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); builder.ApplyConfigurationsFromAssembly(this.GetType().Assembly); } } |
如果需要对User(用户)和Role(角色)进行扩展可进行继承
public class Role:IdentityRole<long> //泛型类型long是Id类型 { }
public class User:IdentityUser<long> { public DateTime CreationTime { get; set; } //创建时间 public string? NickName { get; set; } //昵称 } |
向依赖注入容器中注册标识框架相关的服务
builder.Services.AddDataProtection(); //注意不是AddIdentity 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;//长度为6 options.Tokens.PasswordResetTokenProvider = TokenOptions.DefaultProvider;//设置密码令牌 options.Tokens.EmailConfirmationTokenProvider = TokenOptions.DefaultEmailProvider;//设置邮箱令牌 }); var idBuilder = new IdentityBuilder(typeof(User), typeof(Role), builder.Services); idBuilder.AddEntityFrameworkStores<MyContext>() .AddDefaultTokenProviders().AddRoleManager<RoleManager<Role>>() .AddUserManager<UserManager<User>>(); |
执行Add-Migration、Update-Database等命令执行EF Core的数据库迁移。
Add-Migration Init Update-Database |
创建角色与用户信息
[Route("api/[controller]/[action]")] [ApiController] public class IdentityController : ControllerBase { //通过RoleManager、UserManager等来进行数据操作。比如创建角色、创建用户。 private readonly RoleManager<Role> roleManager; private readonly UserManager<User> userManager; public IdentityController(RoleManager<Role> roleManager, UserManager<User> userManager) { this.roleManager = roleManager; this.userManager = userManager; }
[HttpPost] public async Task<ActionResult> CreateUserRole() { bool roleExists = await roleManager.RoleExistsAsync("admin");//判断是否存在这个角色 if (!roleExists) { Role role = new Role { Name = "Admin" }; var r = await roleManager.CreateAsync(role); //创建失败返回错误信息 if (!r.Succeeded) { return BadRequest(r.Errors); } }
User user = await this.userManager.FindByNameAsync("rodio");//获取某用户信息 if (user == null) { user = new User { UserName = "rodio", Email = "abc123888@gmail.com", EmailConfirmed = true }; var r = await userManager.CreateAsync(user, "123456"); //创建用户信息失败返回错误信息 if (!r.Succeeded) { return BadRequest(r.Errors); } //将角色和用户进行关联 r = await userManager.AddToRoleAsync(user, "admin"); if (!r.Succeeded) { return BadRequest(r.Errors); } } return Ok(); } } |
用户登录
//用户登录类 public record LoginRequest(string UserName,string Password); |
//控制器添加一个Action [HttpPost] public async Task<ActionResult> Login(LoginRequest req) { string userName = req.UserName; string password = req.Password; var user = await userManager.FindByNameAsync(userName);//获取某用户信息 if (user == null)//判断是否存在 { return NotFound($"用户名不存在{userName}"); } //判断该用户是否被锁(封号)了 if (await userManager.IsLockedOutAsync(user)) { return BadRequest("LockedOut"); } //判断用户的账号密码是否成功 var success = await userManager.CheckPasswordAsync(user, password); if (success) { return Ok("Success"); } else { //将用户的登录失败进行计数。如果超过配置次数将会被锁(封号) var r = await userManager.AccessFailedAsync(user); if (!r.Succeeded) { return BadRequest("AccessFailed failed"); } return BadRequest("Failed"); } }
|