【Identity】入门

ASP.NET Core Identity

下文简称Identity,可以理解为用户管理系统,那么它自然是十分强大的,包含用户管理的方方面面,简单的来讲包括:

  • 用户数据存储(使用EF Core对数据库进行操作,因此Identity框架支持几乎所有数据库。)
  • 登陆、注册外加身份认证(基于cookie的身份认证,如果你使用Vs那么还可以生成用于注册登录的用户界面及处理代码)
  • 角色管理
  • 基于声明的认证模式Claims Based Authentication

项目源码:https://gitee.com/core-demo/identity

Identity框架使用

1、安装Nuget包

<PackageReference Include="IdentityModel" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Identity.EntityFrameworkCore" Version="6.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="6.0.5" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="6.0.5">

2、定义用户和角色

IdentityUser<TKey>IdentityRole<TKey>。分别代表用户、角色。TKey代表主键的类型。
我们一般编写继承自IdentityUser、IdentityRole等的自定义类,可以增加自定义属性。

public class MyIdentityUser : IdentityUser<int>
{
    /// <summary>
    /// 新增属性,班级ID
    /// </summary>
    public int ClassID { get; set; }
}
public class MyIdentityRole : IdentityRole<int>
{

}

3、创建继承自IdentityDbContext的类

public class MyIdentityContext : IdentityDbContext<MyIdentityUser, MyIdentityRole, int>
{
    public MyIdentityContext(DbContextOptions<MyIdentityContext> options) : base(options)
    { }
    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        modelBuilder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
    }
}

4、添加数据库连接配置

{
    "ConnectionStrings": {
      "Default": "Server=.;Database=IdentityDB;User ID=sa;Password=123456;"
  }
}

5、注册Identity

IServiceCollection services = builder.Services;
string connStr = builder.Configuration.GetConnectionString("Default");
services.AddDbContext<MyIdentityContext>(opt => {
    opt.UseSqlServer(connStr);
});
services.AddDataProtection();
services.AddIdentityCore<MyIdentityUser>(options => {    //注意不是AddIdentity
    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;
});
var idBuilder = new IdentityBuilder(typeof(MyIdentityUser), typeof(MyIdentityRole), services);
idBuilder.AddEntityFrameworkStores<MyIdentityContext>()
    .AddDefaultTokenProviders()
    .AddRoleManager<RoleManager<MyIdentityRole>>()
    .AddUserManager<UserManager<MyIdentityUser>>();

6、创建迁移文件

Add-Migration

7、自动迁移、添加种子数据

/// <summary>
/// 应用迁移、添加种子数据
/// </summary>
/// <param name="serviceProvider"></param>
/// <exception cref="Exception"></exception>
public static void EnsureSeedData(ServiceProvider serviceProvider)
{
    var services = new ServiceCollection();
    using (var scope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope())
    {
        var context = scope.ServiceProvider.GetService<MyIdentityContext>();
        context.Database.Migrate();

        var userManager = scope.ServiceProvider.GetRequiredService<UserManager<MyIdentityUser>>();
        var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<MyIdentityRole>>();

        IdentityResult result;

        //角色
        bool exist = roleManager.RoleExistsAsync("Admin").Result;
        if (!exist)
        {
            //添加角色
            var role = new MyIdentityRole
            {
                Name = "Admin",
                NormalizedName = "系统管理员"
            };
            result = roleManager.CreateAsync(role).Result;
            if (!result.Succeeded)
            {
                throw new Exception(result.Errors.First().Description);
            }
            //添加角色声明
            result = roleManager.AddClaimAsync(role, new Claim(JwtClaimTypes.Role, "Admin")).Result;

            if (!result.Succeeded)
            {
                throw new Exception(result.Errors.First().Description);
            }
        }

        //用户
        var user = userManager.FindByNameAsync("fan").Result;
        if (user == null)
        {
            user = new MyIdentityUser
            {
                UserName = "fan",
                Email = "410577910@qq.com",
                ClassID = 22
            };
            //添加用户
            result = userManager.CreateAsync(user, "123456").Result;
            if (!result.Succeeded)
            {
                throw new Exception(result.Errors.First().Description);
            }
            //添加用户声明
            result = userManager.AddClaimsAsync(user, new Claim[] {
                new Claim(JwtClaimTypes.Name, "fan"),
                new Claim(JwtClaimTypes.GivenName, "fan"),
                new Claim(JwtClaimTypes.FamilyName, "fan"),
                new Claim(JwtClaimTypes.Email, "410577910@qq.com"),
                new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean),
                new Claim(JwtClaimTypes.WebSite, "http://fan.com"),
                new Claim(JwtClaimTypes.Address, @"{ '城市': '北京', '邮政编码': '10000' }")
            }).Result;
            if (!result.Succeeded)
            {
                throw new Exception(result.Errors.First().Description);
            }
            //用户添加角色
            result = userManager.AddToRoleAsync(user, "Admin").Result;
            if (!result.Succeeded)
            {
                throw new Exception(result.Errors.First().Description);
            }
        }
    }
}

在program中调用SeedData.EnsureSeedData(provider)
部分方法的返回值为Task类型,查看、讲解IdentityResult类型定义。

8、查看数据库

数据库和数据都创建好了

9、实现登录、修改密码功能

可以通过IdDbContext类来操作数据库,不过框架中提供了RoleManager、UserManager等类来简化对数据库的操作。

 // 登录提交
[HttpPost]
public async Task<IActionResult> Login([FromForm] string userName, [FromForm] string password)
{
    var user = await _userManager.FindByNameAsync(userName);
    if (user == null) 
    { 
        return NotFound($"用户名不存在{userName}"); 
    }
    if (await _userManager.IsLockedOutAsync(user))
    {
        return BadRequest("被锁定");
    }
    bool success = await _userManager.CheckPasswordAsync(user, password);
    if (success)
    {
        await _userManager.ResetAccessFailedCountAsync(user);
        return Ok("success");
    }
    else {
        await _userManager.AccessFailedAsync(user);
        return BadRequest("密码错误");
    }
    return View();
}

其他功能可以参考项目源码

参考:
https://www.cnblogs.com/rocketRobin/p/9070684.html

posted @ 2022-04-22 22:28  .Neterr  阅读(547)  评论(1)    收藏  举报