Asp.Net Core鉴权授权:标识框架identity
在一个系统中,不是所有功能都能被自由地访问的,比如有的功能需要注册用户才能访问,有的功能需要VIP用户才能访问。针对资源的访问限制有两个概念:Authentication与Authorization,即鉴权与授权。
- Authentication:用来对访问者的用户身份进行验证;
- Authorization:用来验证访问者的用户身份是否有对资源进行访问的权限。
通俗来说,Authentication是用来验证“用户是否登录成功”的,Authorization是用来验证“用户是否有权限访问”的。
标识框架identity
大部分系统中都需要通过数据库保存用户、角色等信息,并且需要注册、登录、密码重置、角色管理等功能。ASP.NET Core提供了标识(identity)框架,它采用RBAC(role-based access control,基于角色的访问控制)策略,内置了对用户、角色等表的管理及相关的接口,从而简化了系统的开发。标识框架还提供了对外部登录的支持。
标识框架中提供了IdentityUser<TKey>
、IdentityRole<TKey>
两个实体类型,其中的TKey代表主键的类型,因此IdentityUser<Guid>
就代表使用Guid类型主键的用户实体类。
接下来我们开始动手创建项目:
1.创建ASP.NET Core Web API项目,并通过NuGet安装Microsoft.AspNetCore.Identity.EntityFrameworkCore
。
2.创建用户实体类User和角色实体类Role。
public class User : IdentityUser<long> { public DateTime CreationTime { get; set; } public string? NickName { get; set; } } public class Role : IdentityRole<long> { }
IdentityUser中定义了UserName(用户名)、Email(邮箱)、PhoneNumber(手机号)、PasswordHash(密码的哈希值)等属性,我们在User中又添加了CreationTime(创建时间)、NickName(昵称)两个属性。
除了IdentityUser和IdentityRole之外,标识框架中还有很多其他实体类,比如IdentityRoleClaim、IdentityUserClaim、IdentityUserLogin、IdentityUserToken等,一般情况下,我们不需要再编写这些实体类的子类。这些实体类有默认的表名,如果需要修改默认的表名或者对实体类进行进一步的配置,我们可以用EF Core中提供的IEntityTypeConfiguration来对实体类进行配置。
3.创建继承自IdentityDbContext的类,这是一个EF Core中的上下文类,我们可以通过这个类操作数据库。IdentityDbContext是一个泛型类,有3个泛型参数,分别代表用户类型、角色类型和主键类型。
public class IdDbContext : IdentityDbContext<User, Role, long> { public IdDbContext(DbContextOptions<IdDbContext> options): base(options) { } protected override void OnModelCreating(ModelBuilder modelBuilder) { base.OnModelCreating(modelBuilder); modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly); } }
我们可以直接通过IdDbContext类来操作数据库,不过标识框架中提供了RoleManager、UserManager等类来简化对数据库的操作,这些类封装了对IdentityDbContext的操作。
标识框架中的方法有执行失败的可能,比如重置密码可能由于密码太简单而失败,因此标识框架中部分方法的返回值为Task
4.我们需要向依赖注入容器中注册与标识框架相关的服务,并且对相关的选项进行配置。
var builder = WebApplication.CreateBuilder(args); builder.Services.AddControllers(); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); IServiceCollection services = builder.Services; //对IdDbContext进行配置 services.AddDbContext<IdDbContext>(opt => { string connStr = builder.Configuration.GetConnectionString("Default"); opt.UseSqlServer(connStr); }); services.AddDataProtection(); //调用AddIdentityCore添加标识框架的一些重要的基础服务 //(我们没有调用AddIdentity方法,因为AddIdentity方法实现的初始化 // 比较适合传统的MVC模式的项目,而现在我们推荐用前后端分离开发模式。) 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; }); var idBuilder = new IdentityBuilder(typeof(User), typeof(Role), services); //因为UserManager、RoleManager等服务被创建的时候需要注入非常多的服务, //所以我们在使用标识框架的时候也需要注入和初始化非常多的服务 idBuilder.AddEntityFrameworkStores<IdDbContext>() .AddDefaultTokenProviders() .AddRoleManager<RoleManager<Role>>() .AddUserManager<UserManager<User>>(); var app = builder.Build(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); app.UseAuthorization(); app.MapControllers(); app.Run();
还需安装Microsoft.EntityFrameworkCore.SqlServer
包。并在配置文件中写入数据库连接字符串。
"ConnectionStrings": { "Default": "Data Source=.;Database=Customers;User ID=sa;Password=123456;MultipleActiveResultSets=True;" }
5.通过安装Microsoft.EntityFrameworkCore.Tools
包。然后执行数据库迁移Add-Migration createIdentity
、Update-database
等命令执行EF Core的数据库迁移,然后程序就会在数据库中生成多张数据库表。这些数据库表都由标识框架负责管理,开发人员一般不需要直接访问这些表。
6.编写控制器的代码。我们在控制器中需要对角色、用户进行操作,也需要输出日志,因此通过控制器的构造方法注入相关的服务。
[ApiController] [Route("[controller]/[action]")] public class TestController : Controller { private readonly ILogger<TestController> _logger; private readonly UserManager<User> _userManager; private readonly RoleManager<Role> _roleManager; public TestController(ILogger<TestController> logger, UserManager<User> userManager, RoleManager<Role> roleManager) { _logger = logger; _userManager = userManager; _roleManager = roleManager; } ...... }
7.编写创建角色和用户的方法。
[HttpPost] public async Task<IActionResult> 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 _userManager.FindByNameAsync("lf"); if (user == null) { user = new User { UserName = "lf", Email = "389815117@qq.com", EmailConfirmed = true, }; var r = await _userManager.CreateAsync(user, "111111"); if (!r.Succeeded) { return BadRequest(r.Errors); } // 为用户添加角色 r = await _userManager.AddToRoleAsync(user, "admin"); if (!r.Succeeded) { return BadRequest(r.Errors); } } return Ok(); }
8.编写处理登录请求的操作方法Login。
public record LoginRequest(string UserName, string Password);
[HttpPost] public async Task<IActionResult> Login(LoginRequest loginRequest) { string userName = loginRequest.UserName; string password = loginRequest.Password; var user = await _userManager.FindByNameAsync(userName); if (user == null) { return NotFound($"用户名{userName}不存在!"); } var islocked = await _userManager.IsLockedOutAsync(user); if (islocked) { return BadRequest("用户已锁定!"); } var success = await _userManager.CheckPasswordAsync(user, password); if (success) { return Ok(); } else { var r = await _userManager.AccessFailedAsync(user); if (!r.Succeeded) { return BadRequest("访问失败信息写入错误!"); } else { return BadRequest("失败!"); } } }
本文学习参考自:ASP.NET Core技术内幕与项目实战
本文来自博客园,作者:一纸年华,转载请注明原文链接:https://www.cnblogs.com/nullcodeworld/p/16717260.html
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 记一次.NET内存居高不下排查解决与启示
· DeepSeek 开源周回顾「GitHub 热点速览」
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了