ASP.NET Core 标识(Identity)框架系列(一):如何使用 ASP.NET Core 标识(Identity)框架创建用户和角色?

Coding-12

前言

ASP.NET Core 内置的标识(identity)框架,采用的是 RBAC(role-based access control,基于角色的访问控制)策略,是一个用于管理用户身份验证、授权和安全性的框架。

它提供了一套工具和库,用于管理用户、角色、登录、密码重置、电子邮件确认等功能。

通过它,你可以:

  1. 用户管理:创建、管理和验证用户,这样你可以轻松操作注册用户、登录、注销、密码重置等功能。

  2. 角色管理:定义不同的用户角色,并将用户分配到这些角色中,这样你可以更好地控制用户的权限和访问级别。

  3. 密码策略:框架提供了密码策略功能,允许你定义密码的复杂度要求,例如密码长度、大小写字母、数字等要求。

  4. 外部登录:框架还支持你使用外部身份验证提供者(如 QQ、微信、微博等)进行身份验证。

  5. 电子邮件确认:通过电子邮件确认用户注册和密码重置操作,这样注册和修改密码操作更加安全可靠。

今天,我们主要聊聊如何使用 ASP.NET Core 标识(Identity)框架来管理用户和角色,也有涉及到密码策略、电子邮件确认等方面。

Step By Step 步骤

  1. 创建一个 ASP.NET Core webapi 项目,命名为 IdentitySample

  2. 引用以下 Nuget 包:

    Microsoft.AspNetCore.Identity.EntityFrameworkCore
    Microsoft.EntityFrameworkCore.Relational
    Microsoft.EntityFrameworkCore.SqlServer
    Microsoft.EntityFrameworkCore.Tools

  3. 修改 appsettings.json,添加数据库连接字符串

    {
    "Logging": {
    "LogLevel": {
    "Default": "Information",
    "Microsoft.AspNetCore": "Warning"
    }
    },
    "AllowedHosts": "*",
    "ConnectionStrings": {
    "Default": "Server=(localdb)\\mssqllocaldb;Database=IdentityTestDB;Trusted_Connection=True;MultipleActiveResultSets=true"
    }
    }
  4. 创建用户实体类 User(重点看注释

    using Microsoft.AspNetCore.Identity;
    // IdentityUser<long> 表示 long 类型主键的用户实体类
    // IdentityUser 中定义了 UserName(用户名)、Email(邮箱)、PhoneNumber(手机号)、PasswordHash(密码的哈希值)等属性,
    // 这里又添加了 CreationTime(创建时间)、NickName(昵称)两个属性。
    public class User: IdentityUser<long>
    {
    public DateTime CreationTime { get; set; }
    public string? NickName { get; set; }
    }
  5. 创建角色实体类 Role

    using Microsoft.AspNetCore.Identity;
    public class Role: IdentityRole<long>
    {
    }
  6. 创建继承自 IdentityDbContext 的上下文类(重点看注释

    using Microsoft.EntityFrameworkCore;
    using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
    // 使用 Identity 框架要继承 IdentityDbContext
    // 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);
    }
    }
  7. 打开 Program.cs 文件,向依赖注入容器中注册与标识框架相关的服务,并且对相关的选项进行配置(重点看注释

    using Microsoft.AspNetCore.Identity;
    using Microsoft.EntityFrameworkCore;
    var builder = WebApplication.CreateBuilder(args);
    // Add services to the container.
    builder.Services.AddControllers();
    // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
    builder.Services.AddEndpointsApiExplorer();
    builder.Services.AddSwaggerGen();
    // 向依赖注入容器中注册与标识框架相关的服务,并对相关的选项进行配置
    // ----1. 数据库注入
    IServiceCollection services = builder.Services;
    services.AddDbContext<IdDbContext>(opt =>
    {
    string connStr = builder.Configuration.GetConnectionString("Default")!;
    opt.UseSqlServer(connStr);
    });
    // ----2. 数据保护服务注入
    // ----数据保护提供了一个简单、基于非对称加密改进的加密API用于确保Web应用敏感数据的安全存储
    // ----不需要开发人员自行生成密钥,它会根据当前应用的运行环境,生成该应用独有的一个私钥
    services.AddDataProtection();
    // ----3. 添加标识框架的一些重要的基础服务
    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;
    });
    // ----4. 注入 UserManager、RoleManager等服务
    var idBuilder = new IdentityBuilder(typeof(User), typeof(Role), services);
    idBuilder.AddEntityFrameworkStores<IdDbContext>()
    .AddDefaultTokenProviders()
    .AddRoleManager<RoleManager<Role>>()
    .AddUserManager<UserManager<User>>();
    var app = builder.Build();
    // Configure the HTTP request pipeline.
    if (app.Environment.IsDevelopment())
    {
    app.UseSwagger();
    app.UseSwaggerUI();
    }
    app.UseHttpsRedirection();
    app.UseAuthorization();
    app.MapControllers();
    app.Run();
  8. 执行以下命令进行数据迁移,执行后将在数据库中生成多张与 Identity 相关的表

    Add-Migration InitIdentity
    Update-database
  9. 创建相应的实体类

    public record LoginRequest(string UserName, string Password);
    public record SendResetPasswordTokenRequest(string Email);
    public record ResetPasswordResponse(string Email, string Token, string NewPassword);
  10. 在控制器中编写代码,操作角色、用户数据(重点看注释

    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Identity;
    namespace IdentitySample.Controllers
    {
    [ApiController]
    [Route("[controller]/[action]")]
    public class Test1Controller : ControllerBase
    {
    private readonly ILogger<Test1Controller> logger;
    private readonly RoleManager<Role> roleManager;
    private readonly UserManager<User> userManager;
    // 注入 RoleManager,UserManager,ILogger
    public Test1Controller(
    ILogger<Test1Controller> logger,
    RoleManager<Role> roleManager,
    UserManager<User> userManager)
    {
    this.logger = logger;
    this.roleManager = roleManager;
    this.userManager = userManager;
    }
    // 创建角色和用户
    [HttpPost]
    public async Task<ActionResult> CreateUserRole()
    {
    // 1. 判断管理员角色是否存在,不存在则创建
    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);
    }
    }
    // 2. 创建账户
    User user = await userManager.FindByNameAsync("yzk");
    if (user == null)
    {
    user = new User
    {
    UserName = "yzk",
    Email = "51398898@qq.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();
    }
    // 登录
    [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
    {
    // 调用userManager的AccessFailedAsync方法来记录一次“登录失败”,
    // 当连续多次登录失败之后,账户就会被锁定一段时间,以避免账户被暴力破解
    var r = await userManager.AccessFailedAsync(user);
    if (!r.Succeeded)
    {
    return BadRequest("AccessFailed failed");
    }
    return BadRequest("Failed");
    }
    }
    // 发送重置密码 Token
    [HttpPost]
    public async Task<IActionResult> SendResetPasswordToken(
    SendResetPasswordTokenRequest req)
    {
    string email = req.Email;
    var user = await userManager.FindByEmailAsync(email);
    if (user == null)
    {
    return NotFound($"邮箱不存在:[{email}]");
    }
    // 调用GeneratePasswordResetTokenAsync方法来生成一个密码重置令牌,这个令牌会被保存到数据库中
    // 然后把这个令牌发送到用户邮箱
    string token = await userManager.GenerateEmailConfirmationTokenAsync(user);
    logger.LogInformation($"向邮箱{user.Email}发送Token={token}");
    return Ok(token);
    }
    // 重置密码
    [HttpPost]
    public async Task<IActionResult> VerifyResetPasswordToken(
    ResetPasswordRequest req)
    {
    string email = req.Email;
    var user = await userManager.FindByEmailAsync(email);
    string token = req.Token;
    string password = req.NewPassword;
    var r = await userManager.ResetPasswordAsync(user, token, password);
    return Ok();
    }
    }
    }
  11. 启动项目,通过 Postman 或 Swagger 运行 API 进行测试

最后

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

往期精彩

  1. C# 静态类,高手不想让你知道的 15 个真相
  2. 封装一个 C# 范围判断函数,从此告别重复编写范围判断代码的烦恼
  3. 用 C# Stopwatch 计时,让代码性能飞起来!
  4. 轻装上阵,Visual Studio LocalDB:.NET 程序员的本地数据库神器
  5. 封装一个C#万能基础数据类型转换器,一招解决所有基础类型转换烦恼
  6. 闲话 .NET(7):.NET Core 能淘汰 .NET FrameWork 吗?
  7. 常用的 4 种 ORM 框架(EF Core,SqlSugar,FreeSql,Dapper)对比总结
  8. C# AutoMapper 10个常用方法总结
  9. C# 7个方法比较两个对象是否相等
  10. C# 去掉字符串最后一个字符的 4 种方法

image

posted @   代码掌控者  阅读(200)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· 上周热点回顾(2.17-2.23)
· 如何使用 Uni-app 实现视频聊天(源码,支持安卓、iOS)
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
点击右上角即可分享
微信分享提示