ASP.NET Core标识框架Identity

目录

Authentication与Authorization

标识框架(Identity)

Identity框架的使用

初始化

自定义属性

案例一:添加用户、角色

案例二:检查登录用户信息

案例三:实现密码的重置

步骤


Authentication与Authorization

Authentication对访问者的用户身份进行验证,"用户是否登录成功"。

Authorization验证访问者的用户身份是否有对资源访问的访问权限,"用户是否有权限访问这个地址"。

标识框架(Identity)

标识(Identity)框架:采用基于角色的访问控制(Role-Based Access Control,简称RBAC)策略,内置了对用户、角色等表的管理以及相关的接口,支持外部登录、2FA等。

标识框架使用EF Core对数据库进行操作,因此标识框架支持几乎所有数据库。

Identity框架的使用

  1. IdentityUser<TKey>、IdentityRole<TKey>,TKey代表主键的类型。我们一般编写继承自IdentityUser<TKey>、IdentityRole<TKey>等的自定义类,可以增加自定义属性。
  2. NuGet:Microsoft.AspNetCore.Identity.EntityFrameworkCore。
  3. 创建继承自IdentityDbContext的类
  4. 可以通过IdDbContext类来操作数据库,不过框架中提供了RoleManager、UserManager等类来简化对数据库的操作。
  5. 部分方法的返回值为Task<IdentityResult>类型

初始化

初始化完执行数据库迁移操作

cs 复制代码
public class MyUser:IdentityUser<long>
{
}
public class MyRole:IdentityRole<long>
{
}
public class MyDbContext:IdentityDbContext<MyUser,MyRole,long>
{
    public MyDbContext(DbContextOptions<MyDbContext> options) : base(options)
    {
    }
}

Program.cs
//添加数据库上下文
builder.Services.AddDbContext<MyDbContext>(opt => {
    string connStr = Environment.GetEnvironmentVariable("ConnStr");
    opt.UseSqlServer(connStr);
});
//添加数据保护服务
builder.Services.AddDataProtection();
//添加身份认证服务
builder.Services.AddIdentityCore<MyUser>(options => {
    //设置密码规则,不需要数字,小写字母,大写字母,特殊字符,长度为6
    options.Password.RequireDigit = false;
    options.Password.RequireLowercase = false;
    options.Password.RequireUppercase = false;
    options.Password.RequireNonAlphanumeric = false;
    options.Password.RequiredLength = 6;
    //设置密码重置令牌提供程序为默认的电子邮件提供程序
    options.Tokens.PasswordResetTokenProvider = TokenOptions.DefaultEmailProvider;
    //设置电子邮件确认令牌提供程序为默认的电子邮件提供程序
    options.Tokens.EmailConfirmationTokenProvider = TokenOptions.DefaultEmailProvider;
});
//添加实体框架、默认令牌提供程序、角色管理器、用户管理器
var idBuilder = new IdentityBuilder(typeof(MyUser), typeof(MyRole), builder.Services);
idBuilder.AddEntityFrameworkStores<MyDbContext>().AddDefaultTokenProviders()
    .AddRoleManager<RoleManager<MyRole>>().AddUserManager<UserManager<MyUser>>();

自定义属性

cs 复制代码
public class MyUser:IdentityUser<long>
{
    public string? WeChatAccout { get; set; }
}

案例一:添加用户、角色

通过RoleManager、UserManager等来进行数据操作,创建用户:小明,角色:admin,为小明添加admin角色

cs 复制代码
[Route("api/[controller]/[action]")]
[ApiController]
public class DemoContrller : ControllerBase
{
    private readonly UserManager<MyUser> userManager;
    private readonly RoleManager<MyRole> roleManager;

    public DemoContrller(UserManager<MyUser> userManager, RoleManager<MyRole> roleManager)
    {
        this.userManager = userManager;
        this.roleManager = roleManager;
    }

    [HttpPost]
    public async Task<ActionResult<string>> Test1()
    {
        if (!await roleManager.RoleExistsAsync("admin"))
        {
            var result = await roleManager.CreateAsync(new MyRole { Name = "admin" });
            if (!result.Succeeded)
            {
                return BadRequest("角色创建失败");
            }
        }
        MyUser user1 = await userManager.FindByNameAsync("小明");
        if (user1 == null)
        {
            var result = await userManager.CreateAsync(new MyUser { UserName = "小明" }, "123456");
            if (!result.Succeeded)
            {
                return BadRequest("用户创建失败");
            }
        }
        if(!await userManager.IsInRoleAsync(user1, "admin"))
        {
            var result = await userManager.AddToRoleAsync(user1, "admin");
            if (!result.Succeeded)
            {
                return BadRequest("用户添加角色失败");
            }
        }
        return Ok("测试成功");
    }
}

案例二:检查登录用户信息

userManager.AccessFailedAsync记录"登录失败",多次失败后,会被锁定一段时间,以避免账号被暴力破解,默认锁定时间5分钟,失败次数5次,,可以在Program.cs中设置options.Lockout.DefaultLockoutTimeSpan和options.Lockout.MaxFailedAccessAttempts来修改默认值

cs 复制代码
[HttpPost]
public async Task<ActionResult<string>> Test2(CheckPwdRequest req)
{
    string userName = req.UserName;
    string password = req.Password;
    var user = await userManager.FindByNameAsync(userName);
    if (user == null)
    {
        return BadRequest("用户或密码错误");
    }
    //await userManager.ResetAccessFailedCountAsync(user);
    if (await userManager.IsLockedOutAsync(user))
    {
        DateTimeOffset lockout = (DateTimeOffset)user.LockoutEnd + new TimeSpan(8, 0, 0);
        return BadRequest(DateTime.Now + "用户已被锁定,解锁时间" + lockout);
    }
    if (await userManager.CheckPasswordAsync(user, password))
    {
        await userManager.ResetAccessFailedCountAsync(user);
        return Ok("登录成功");
    }
    else
    {
        await userManager.AccessFailedAsync(user);
        return BadRequest("用户或密码错误");
    }
}

案例三:实现密码的重置

调用GeneratePasswordResetTokenAsync方法来生成密码重置令牌,实际项目中,邮件发送一般调用邮件服务提供商的接口,这里只是简单输出到控制台,默认生成的令牌很长,我们可以在Project.cs设置options.Tokens.PasswordResetTokenProvider属性的值

步骤
  1. 生成重置Token
  2. Token发给客户(邮件、短信等),形式:链接、验证码等。
  3. 根据Token完成密码的重置。
cs 复制代码
[HttpPost]
public async Task<ActionResult> SendResetPasswordToken(string userName)
{
    var user = await userManager.FindByNameAsync(userName);
    if (user == null)
    {
        return BadRequest("用户名不存在!");
    }
    string token = await userManager.GeneratePasswordResetTokenAsync(user);
    Console.WriteLine($"向邮箱{user.Email}发送Token={token}");
    return Ok(token);
}

[HttpPut]
public async Task<ActionResult> ResetPassword(string userName, string token, string newPassword)
{
    var user = await userManager.FindByNameAsync(userName);
    if (user == null)
    {
        return BadRequest("用户名不存在!");
    }
    var result = await userManager.ResetPasswordAsync(user, token, newPassword);
    if (result.Succeeded)
    {
        await userManager.ResetAccessFailedCountAsync(user);
        return Ok("密码重置成功");
    }
    else
    {
        await userManager.AccessFailedAsync(user);
        return BadRequest("密码重置失败");
    }
}
相关推荐
FungLeo2 天前
成为全栈·React 管理后台篇·按钮级权限:能力映射、菜单过滤与自锁保护
react·rbac·路由守卫·权限控制·前端权限·成为全栈
金士顿3 天前
ASP.NET Core Native AOT + systemd 实战:把 Linux ARM64 程序变成可靠的设备服务
linux·嵌入式·asp.net core·arm64
金士顿3 天前
System.Text.Json Source Generator 深度解析:为什么 Native AOT 不喜欢反射
linux·asp.net core·arm64·net·native aot
金士顿3 天前
ASP.NET Core Native AOT 到底是什么?从 C#、IL、JIT 一直讲到 Linux ARM64 ELF
嵌入式·asp.net core
金士顿7 天前
ASP.NET Core BackgroundService 深度解析:设备后台任务到底应该怎么设计
linux·嵌入式·asp.net core·arm64
RuoyiOffice7 天前
SpringBoot3+Vue3 企业级管理平台架构:多租户、RBAC、数据权限、工作流与微服务一次讲透
spring boot·vue3·springboot3·rbac·多租户·数据权限·ruoyi office
FungLeo18 天前
成为全栈·Node 后端篇·权限模型:从认证到 RBAC
node.js·rbac·用户认证·权限模型·成为全栈
pnoker24 天前
IoT DC3 安全设计:四层纵深防御体系
物联网·安全·rbac
蒲锘1 个月前
DevOps 实验项目笔记三 —— Kubernetes 集群部署阶段
笔记·kubernetes·devops·rbac
JonLee20202 个月前
适配 Yii 3.0,php-casbin/yii-permission 3.0 正式发布
安全·php·rbac·yii·权限·casbin