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技术内幕与项目实战》一书中内容,此文只是做学习记录,如有侵权,联系立马删除。