东湖之滨 发表于 2024-11-22 17:38:01

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

https://img2024.cnblogs.com/blog/3351211/202411/3351211-20241122175931176-1513843342.png
媒介

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,添加数据库毗连字符串
{
"Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft.AspNetCore": "Warning"
        }
},
"AllowedHosts": "*",
"ConnectionStrings": {
        "Default": "Server=(localdb)\\mssqllocaldb;Database=IdentityTestDB;Trusted_Connection=True;MultipleActiveResultSets=true"
}
}       
[*]创建用户实体类 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; }
}
[*]创建角色实体类 Role
using Microsoft.AspNetCore.Identity;

public class Role: IdentityRole<long>
{

}
[*]创建继承自 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);
        }
}       
[*]打开 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();
[*]执行以下命令进行数据迁徙,执行后将在数据库中生成多张与 Identity 相关的表
Add-Migration InitIdentity
Update-database
[*]创建相应的实体类
public record LoginRequest(string UserName, string Password);

public record SendResetPasswordTokenRequest(string Email);

public record ResetPasswordResponse(string Email, string Token, string NewPassword);
[*]在控制器中编写代码,操作角色、用户数据(重点看注释)
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Identity;

namespace IdentitySample.Controllers
{
       
        /")]
        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;
                }

                // 创建角色和用户
               
                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();
                }

                // 登录
               
                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
               
                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);
                }

                // 重置密码
               
                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();
                }
        }
}       
[*]启动项目,通过 Postman 或 Swagger 运行 API 进行测试
最后

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


[*]C# 静态类,高手不想让你知道的 15 个真相
[*]封装一个 C# 范围判断函数,今后告别重复编写范围判断代码的烦恼
[*]用 C# Stopwatch 计时,让代码性能飞起来!
[*]轻装上阵,Visual Studio LocalDB:.NET 程序员的当地数据库神器
[*]封装一个C#全能基础数据范例转换器,一招解决所有基础范例转换烦恼
[*]闲话 .NET(7):.NET Core 能淘汰 .NET FrameWork 吗?
[*]常用的 4 种 ORM 框架(EF Core,SqlSugar,FreeSql,Dapper)对比总结
[*]C# AutoMapper 10个常用方法总结
[*]C# 7个方法比较两个对象是否相称
[*]C# 去掉字符串最后一个字符的 4 种方法
https://img2024.cnblogs.com/blog/3351211/202409/3351211-20240920180709919-918692799.gif

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: ASP.NET Core 标识(Identity)框架系列(一):怎样使用 ASP.NET Core 标