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("密码重置失败");
    }
}
相关推荐
lixww.cn1 天前
ASP.NET Core中间件Markdown转换器
中间件·markdown·asp.net core
咩咩大主教16 天前
Go语言通过Casbin配合MySQL和Gorm实现RBAC访问控制模型
mysql·golang·鉴权·go语言·rbac·abac·casbin
啊晚1 个月前
ASP.NET Core - 日志记录系统(二)
asp.net core
VAllen1 个月前
分析基于ASP.NET Core Kernel的gRPC服务在不同.NET版本的不同部署方式的不同线程池下的性能表现
.net·性能测试·asp.net core·grpc·dotnet
棉晗榜2 个月前
.net core在linux导出excel,System.Drawing.Common is not supported on this platform
linux·excel·asp.net core·miniexcel
棉晗榜2 个月前
asp.net core发布配置端口号,支持linux
asp.net core
coredx2 个月前
如何优雅地让 ASP.NET Core 支持异步模型验证
asp.net core
小乖兽技术2 个月前
ASP.NET Core Web 项目的部署:选择 IIS 还是 Kestrel?
后端·kestrel·iis·asp.net·asp.net core
界面开发小八哥2 个月前
DevExtreme JS & ASP.NET Core v24.2新功能预览 - 全新的聊天组件
javascript·ui·asp.net core·界面控件·ui开发·devextreme·.net 9