ASP.NET Core 标识(Identity)框架系列(一):怎样使用 ASP.NET Core 标 ...

打印 上一主题 下一主题

主题 934|帖子 934|积分 2806


媒介

ASP.NET Core 内置的标识(identity)框架,采用的是 RBAC(role-based access control,基于角色的访问控制)计谋,是一个用于管理用户身份验证、授权和安全性的框架。
它提供了一套工具和库,用于管理用户、角色、登录、暗码重置、电子邮件确认等功能。
通过它,你可以:

  • 用户管理:创建、管理和验证用户,这样你可以轻松操作注册用户、登录、注销、暗码重置等功能。
  • 角色管理:定义不同的用户角色,并将用户分配到这些角色中,这样你可以更好地控制用户的权限和访问级别。
  • 暗码计谋:框架提供了暗码计谋功能,允许你定义暗码的复杂度要求,例如暗码长度、大小写字母、数字等要求。
  • 外部登录:框架还支持你使用外部身份验证提供者(如 QQ、微信、微博等)进行身份验证。
  • 电子邮件确认:通过电子邮件确认用户注册和暗码重置操作,这样注册和修改暗码操作更加安全可靠。
今天,我们主要聊聊怎样使用 ASP.NET Core 标识(Identity)框架来管理用户和角色,也有涉及到暗码计谋、电子邮件确认等方面。
Step By Step 步调


  • 创建一个 ASP.NET Core webapi 项目,定名为 IdentitySample
  • 引用以下 Nuget 包:
    Microsoft.AspNetCore.Identity.EntityFrameworkCore
    Microsoft.EntityFrameworkCore.Relational
    Microsoft.EntityFrameworkCore.SqlServer
    Microsoft.EntityFrameworkCore.Tools

  • 修改 appsettings.json,添加数据库毗连字符串
    1. {
    2.   "Logging": {
    3.         "LogLevel": {
    4.           "Default": "Information",
    5.           "Microsoft.AspNetCore": "Warning"
    6.         }
    7.   },
    8.   "AllowedHosts": "*",
    9.   "ConnectionStrings": {
    10.         "Default": "Server=(localdb)\\mssqllocaldb;Database=IdentityTestDB;Trusted_Connection=True;MultipleActiveResultSets=true"
    11.   }
    12. }       
    复制代码
  • 创建用户实体类 User(重点看注释
    1. using Microsoft.AspNetCore.Identity;
    2. // IdentityUser<long> 表示 long 类型主键的用户实体类
    3. // IdentityUser 中定义了 UserName(用户名)、Email(邮箱)、PhoneNumber(手机号)、PasswordHash(密码的哈希值)等属性,
    4. // 这里又添加了 CreationTime(创建时间)、NickName(昵称)两个属性。
    5. public class User: IdentityUser<long>
    6. {
    7.         public DateTime CreationTime { get; set; }
    8.         public string? NickName { get; set; }
    9. }
    复制代码
  • 创建角色实体类 Role
    1. using Microsoft.AspNetCore.Identity;
    2. public class Role: IdentityRole<long>
    3. {
    4. }
    复制代码
  • 创建继承自 IdentityDbContext 的上下文类(重点看注释
    1. using Microsoft.EntityFrameworkCore;
    2. using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
    3. // 使用 Identity 框架要继承 IdentityDbContext
    4. // IdentityDbContext 是一个泛型类,有3个泛型参数,分别代表用户类型、角色类型和主键类型
    5. public class IdDbContext: IdentityDbContext<User, Role, long>
    6. {
    7.         public IdDbContext(DbContextOptions<IdDbContext> options) : base(options)
    8.         {
    9.         }
    10.         protected override void OnModelCreating(ModelBuilder modelBuilder)
    11.         {
    12.                 base.OnModelCreating(modelBuilder);
    13.                 modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
    14.         }
    15. }       
    复制代码
  • 打开 Program.cs 文件,向依赖注入容器中注册与标识框架相关的服务,而且对相关的选项进行设置(重点看注释
    1. using Microsoft.AspNetCore.Identity;
    2. using Microsoft.EntityFrameworkCore;
    3. var builder = WebApplication.CreateBuilder(args);
    4. // Add services to the container.
    5. builder.Services.AddControllers();
    6. // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
    7. builder.Services.AddEndpointsApiExplorer();
    8. builder.Services.AddSwaggerGen();
    9. // 向依赖注入容器中注册与标识框架相关的服务,并对相关的选项进行配置
    10. // ----1. 数据库注入
    11. IServiceCollection services = builder.Services;
    12. services.AddDbContext<IdDbContext>(opt =>
    13. {
    14.         string connStr = builder.Configuration.GetConnectionString("Default")!;
    15.         opt.UseSqlServer(connStr);
    16. });
    17. // ----2. 数据保护服务注入
    18. // ----数据保护提供了一个简单、基于非对称加密改进的加密API用于确保Web应用敏感数据的安全存储
    19. // ----不需要开发人员自行生成密钥,它会根据当前应用的运行环境,生成该应用独有的一个私钥
    20. services.AddDataProtection();
    21. // ----3. 添加标识框架的一些重要的基础服务
    22. services.AddIdentityCore<User>(options => {
    23.         options.Password.RequireDigit = false;
    24.         options.Password.RequireLowercase = false;
    25.         options.Password.RequireNonAlphanumeric = false;
    26.         options.Password.RequireUppercase = false;
    27.         options.Password.RequiredLength = 6;
    28.         options.Tokens.PasswordResetTokenProvider = TokenOptions.DefaultEmailProvider;
    29.         options.Tokens.EmailConfirmationTokenProvider = TokenOptions.DefaultEmailProvider;
    30. });
    31. // ----4. 注入 UserManager、RoleManager等服务
    32. var idBuilder = new IdentityBuilder(typeof(User), typeof(Role), services);
    33. idBuilder.AddEntityFrameworkStores<IdDbContext>()
    34.         .AddDefaultTokenProviders()
    35.         .AddRoleManager<RoleManager<Role>>()
    36.         .AddUserManager<UserManager<User>>();
    37. var app = builder.Build();
    38. // Configure the HTTP request pipeline.
    39. if (app.Environment.IsDevelopment())
    40. {
    41.         app.UseSwagger();
    42.         app.UseSwaggerUI();
    43. }
    44. app.UseHttpsRedirection();
    45. app.UseAuthorization();
    46. app.MapControllers();
    47. app.Run();
    复制代码
  • 执行以下命令进行数据迁徙,执行后将在数据库中生成多张与 Identity 相关的表
    1. Add-Migration InitIdentity
    2. Update-database
    复制代码
  • 创建相应的实体类
    1. public record LoginRequest(string UserName, string Password);
    2. public record SendResetPasswordTokenRequest(string Email);
    3. public record ResetPasswordResponse(string Email, string Token, string NewPassword);
    复制代码
  • 在控制器中编写代码,操作角色、用户数据(重点看注释
    1. using Microsoft.AspNetCore.Mvc;
    2. using Microsoft.AspNetCore.Identity;
    3. namespace IdentitySample.Controllers
    4. {
    5.         [ApiController]
    6.         [Route("[controller]/[action]")]
    7.         public class Test1Controller : ControllerBase
    8.         {
    9.                 private readonly ILogger<Test1Controller> logger;
    10.                 private readonly RoleManager<Role> roleManager;
    11.                 private readonly UserManager<User> userManager;
    12.                 // 注入 RoleManager,UserManager,ILogger
    13.                 public Test1Controller(
    14.                         ILogger<Test1Controller> logger,
    15.                         RoleManager<Role> roleManager,
    16.                         UserManager<User> userManager)
    17.                 {
    18.                         this.logger = logger;
    19.                         this.roleManager = roleManager;
    20.                         this.userManager = userManager;
    21.                 }
    22.                 // 创建角色和用户
    23.                 [HttpPost]
    24.                 public async Task<ActionResult> CreateUserRole()
    25.                 {
    26.                         // 1. 判断管理员角色是否存在,不存在则创建
    27.                         bool roleExists = await roleManager.RoleExistsAsync("admin");
    28.                         if (!roleExists)
    29.                         {
    30.                                 Role role = new Role() { Name = "Admin" };
    31.                                 var r = await roleManager.CreateAsync(role);
    32.                                 if (!r.Succeeded)
    33.                                 {
    34.                                         return BadRequest(r.Errors);
    35.                                 }
    36.                         }
    37.                         // 2. 创建账户
    38.                         User user = await userManager.FindByNameAsync("yzk");
    39.                         if (user == null)
    40.                         {
    41.                                 user = new User
    42.                                 {
    43.                                         UserName = "yzk",
    44.                                         Email = "51398898@qq.com",
    45.                                         EmailConfirmed = true,
    46.                                 };
    47.                                 var r = await userManager.CreateAsync(user, "123456");
    48.                                 if (!r.Succeeded)
    49.                                 {
    50.                                         return BadRequest(r.Errors);
    51.                                 }
    52.                                 r = await userManager.AddToRoleAsync(user, "Admin");
    53.                                 if (!r.Succeeded)
    54.                                 {
    55.                                         return BadRequest(r.Errors);
    56.                                 }
    57.                         }
    58.                         return Ok();
    59.                 }
    60.                 // 登录
    61.                 [HttpPost]
    62.                 public async Task<ActionResult> Login(LoginRequest req)
    63.                 {
    64.                         string userName = req.UserName;
    65.                         string password = req.Password;
    66.                         var user = await userManager.FindByNameAsync(userName);
    67.                         if (user == null)
    68.                         {
    69.                                 return NotFound($"用户名不存在{userName}");
    70.                         }
    71.                         if (await userManager.IsLockedOutAsync(user))
    72.                         {
    73.                                 return BadRequest("LockedOut");
    74.                         }
    75.                         var success = await userManager.CheckPasswordAsync(user, password);
    76.                         if (success)
    77.                         {
    78.                                 return Ok("Success");
    79.                         }
    80.                         else
    81.                         {
    82.                                 // 调用userManager的AccessFailedAsync方法来记录一次“登录失败”,
    83.                                 // 当连续多次登录失败之后,账户就会被锁定一段时间,以避免账户被暴力破解
    84.                                 var r = await userManager.AccessFailedAsync(user);
    85.                                 if (!r.Succeeded)
    86.                                 {
    87.                                         return BadRequest("AccessFailed failed");
    88.                                 }
    89.                                 return BadRequest("Failed");
    90.                         }
    91.                 }
    92.                 // 发送重置密码 Token
    93.                 [HttpPost]
    94.                 public async Task<IActionResult> SendResetPasswordToken(
    95.                         SendResetPasswordTokenRequest req)
    96.                 {
    97.                         string email = req.Email;
    98.                         var user = await userManager.FindByEmailAsync(email);
    99.                         if (user == null)
    100.                         {
    101.                                 return NotFound($"邮箱不存在:[{email}]");
    102.                         }
    103.                         // 调用GeneratePasswordResetTokenAsync方法来生成一个密码重置令牌,这个令牌会被保存到数据库中
    104.                         // 然后把这个令牌发送到用户邮箱
    105.                         string token = await userManager.GenerateEmailConfirmationTokenAsync(user);
    106.                         logger.LogInformation($"向邮箱{user.Email}发送Token={token}");
    107.                         return Ok(token);
    108.                 }
    109.                 // 重置密码
    110.                 [HttpPost]
    111.                 public async Task<IActionResult> VerifyResetPasswordToken(
    112.                         ResetPasswordRequest req)
    113.                 {
    114.                         string email = req.Email;
    115.                         var user = await userManager.FindByEmailAsync(email);
    116.                         string token = req.Token;
    117.                         string password = req.NewPassword;
    118.                         var r = await userManager.ResetPasswordAsync(user, token, password);
    119.                         return Ok();
    120.                 }
    121.         }
    122. }       
    复制代码
  • 启动项目,通过 Postman 或 Swagger 运行 API 进行测试
最后

ASP.NET Core 内置的标识(identity)框架使用 EF Core 对数据库进行操作
往期精彩



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

东湖之滨

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表