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("密码重置失败");
    }
}
相关推荐
格桑阿sir14 天前
Kubernetes控制平面组件:API Server RBAC授权机制 详解
kubernetes·云计算·rbac·授权·authorization·apiserver·鉴权机制
lixww.cn25 天前
ASP.NET Core用MediatR实现领域事件
ddd·asp.net core·mediatr
lixww.cn1 个月前
ASP.NET Core SignalR向部分客户端发消息
javascript·websocket·vue·asp.net core·signalr
lixww.cn1 个月前
ASP.NET Core SignalR的协议协商
asp.net core·signalr
lixww.cn1 个月前
ASP.NET Core SignalR的分布式部署
redis·消息队列·asp.net core·signalr
lixww.cn1 个月前
ASP.NET Core对JWT的封装
asp.net core·jwt·authorize
lixww.cn1 个月前
ASP.NET Core JWT Version
asp.net core·jwt·filter·identity
lixww.cn1 个月前
ASP.NET Core JWT
asp.net core·jwt
lixww.cn1 个月前
ASP.NET Core中间件Markdown转换器
中间件·markdown·asp.net core