Asp.Net Core 高级 Identity

Identity

Authentication与Authorization

1、Authentication对访问者的用户身份进行验证,“用户是否登录成功”。(用户 User)
2、Authorization验证访问者的用户身份是否有对资源访问的访问权限,“用户是否有权限访问这个地址”。(角色Role)

3、Identity框架:采用基于角色的访问控制(Role-Based Access Control,简称RBAC)策略,内置了对用户、角色等表的管理以及相关的接口,支持外部登录、2FA等。
4、Identity框架使用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等类来简化对数据库的操作。

不使用原生IdentityUser与IdentityRole 自己创建继承他们的实体,方便扩展

MyUser与MyRole
using Microsoft.AspNetCore.Identity;
namespace IdentityStudy.Entity
{
    //long 做主键 自增
    public class MyUser : IdentityUser<long>
    {

    }
}

using Microsoft.AspNetCore.Identity;
namespace IdentityStudy.Entity
{
    //long 做主键 自增
    public class MyRole : IdentityRole<long>
    {

    }
}
MyDbContext
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace IdentityStudy.Entity
{
    public class MyDbContext : IdentityDbContext<MyUser,MyRole,long>
    {
        public MyDbContext(DbContextOptions<MyDbContext> options):base(options)
        {

        }

        protected override void OnModelCreating(ModelBuilder builder)
        {
            base.OnModelCreating(builder);
            builder.ApplyConfigurationsFromAssembly(this.GetType().Assembly);
        }
        
    }
}

Program
using IdentityStudy.Entity;
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();

//var services =  builder.Services;

builder.Services.AddDbContext<MyDbContext>(opt => 
{
    var connStr = $"Host=localhost;Database=Identity;Username=postgres;Password=root";
    opt.UseNpgsql(connStr);

});

builder.Services.AddDataProtection();
//builder.Services.AddIdentity  是MVC 用的 提供了登录以及用户管理的相关页面
builder.Services.AddIdentityCore<MyUser>(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;
});
//与自己的实体对应
var idBuilder = new IdentityBuilder(typeof(MyUser), typeof(MyRole), builder.Services);
idBuilder.AddEntityFrameworkStores<MyDbContext>()
    .AddDefaultTokenProviders()
    //与自己的实体对应
    .AddRoleManager<RoleManager<MyRole>>()
    .AddUserManager<UserManager<MyUser>>();

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();

使用EF Core的迁移数据库的时候,如果出现了类似的错误Unable to create an object of type ‘MyDbContext’. For the different patterns supported at design time, see https://go.microsoft.com/fwlink/?linkid=851728

可以创建一个实现了IDesignTimeDbContextFactory< MyDbContext >的类

MyDesignTimeDbContextFactory
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;

namespace IdentityStudy.Entity
{
    public class MyDesignTimeDbContextFactory : IDesignTimeDbContextFactory<MyDbContext>
    {
        public MyDbContext CreateDbContext(string[] args)
        {
            DbContextOptionsBuilder<MyDbContext> builder = new();
            var connStr = $"Host=localhost;Database=Identity;Username=postgres;Password=root";
            builder.UseNpgsql(connStr);
            return new MyDbContext(builder.Options);
        }
    }
}

可以解决上述问题,此类只是在EF Core Tools使用,不影响生产环境。

重点是:RoleManager UserManager的使用

RoleManager< Role > ;UserManager< User >里面有很多方法名字大多数可以猜想如Create update delete,GetxxxByXXX等等 具体自己使用的时候可以进入程序集看。

TestController
[HttpPost]
		public async Task<ActionResult> CreateUserRole()
		{
			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);
				}
			}
			User user = await this.userManager.FindByNameAsync("first");
			if (user == null)
			{
				user = new User{UserName="yzk",Email="test@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();
		}

		[HttpPost]
		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
			{
				var r = await userManager.AccessFailedAsync(user);
				if (!r.Succeeded)
				{
					return BadRequest("AccessFailed failed");
				}
				return BadRequest("Failed");
			}
		}

		[HttpPost]
		public async Task<IActionResult> SendResetPasswordToken(
					SendResetPasswordTokenRequest req)
		{
			string email = req.Email;
			var user = await userManager.FindByEmailAsync(email);
			if (user == null)
			{
				return NotFound($"邮箱不存在{email}");
			}
			string token = await userManager.GeneratePasswordResetTokenAsync(user);
			logger.LogInformation($"向邮箱{user.Email}发送Token={token}");
			return Ok();
		}

本文内容大部分都为杨中科老师《ASP.NET Core技术内幕与项目实战》一书中内容,此文只是做学习记录,如有侵权,联系立马删除。