.NET IDS4(identityService4)
文章目录
一.引入Identity服务,更新数据表
1.接之前写的文章Efcore教程 之前我们创建好一个AppDbContext类,继承于DbContext,现在改为IdentityDbContext,因为IdentityDbContext继承于DbContext
2.配置ASP.NET Core Identity服务
在ConfigureServices添加:
services.AddIdentity<IdentityUser,IdentityRole>().AddEntityFrameworkStores<AppDbContext>();
3.将Authorization中间件添加到请求管道,代码如下:
点击查看代码
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}else if(env.IsStaging()||env.IsProduction()||env.IsEnvironment("UAT"))
{
app.UseExceptionHandler("/Error");
app.UseStatusCodePagesWithRedirects("/Error/{0}");
}
app.UseStaticFiles();
app.UseRouting();
//添加验证中间件
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name:"default",
pattern: "{controller=Home}/{action=Index}/{id?}"
);
});
}
顺序不能乱!
4.现在开始身份迁移,打开程序包控制台窗口 执行以下命令进行新的迁移(生成迁移文件)
Add-Migration AddingIdentity
此迁移用于创建ASP.NET CORE Identity系统所需的表的代码
如果运行,则会出现以下错误(没有在数据库上下文类中重写OnModelCreating就不会报错,可以跳过这一步), The entity type 'IdentityUserLogin<string>' requires a primary key to be defined
之前因为封装Seed()方法(生成种子数据的方法),所以重写OnModelCreating()方法,但未调用基本IdentityDbContext类OnModelCreating()方法.
Identity表的键映射在IdentityDbContext类的OnModelCreating()方法中,因此,要解决这个错误,需要做的是,调用基类OnModelCreating()使用该方法的关键字,代码如下:
点击查看代码
public class AppDbContext:IdentityDbContext
{
public AppDbContext(DbContextOptions<AppDbContext> options):base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Seed();
}
public DbSet<Student> Students { get; set; }
}
5.再次执行Add-Migration AddingIdentity
发现成功
执行Update-Database
命令更新数据表,即可
6.更新之后的数据表如下:
二.Ids4的注册
1.关于界面的操作我就不过多介绍了,新增一个控制器Account
2.UserManager
点击查看代码
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using MockSchoolManageMent.ViewModels;
using System.Threading.Tasks;
namespace MockSchoolManageMent.Controllers
{
public class AccountController : Controller
{
private readonly UserManager<IdentityUser> userManager;
private readonly SignInManager<IdentityUser> signInManager;
public AccountController(UserManager<IdentityUser> _userManager,
SignInManager<IdentityUser> _signInManager)
{
this.userManager = _userManager;
this.signInManager = _signInManager;
}
[HttpGet]
public IActionResult Register()
{
return View();
}
[HttpPost]
public async Task<IActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
//将数据从RegisterViewModel复制到IdentityUser
var user = new IdentityUser
{
UserName = model.Email,
Email = model.Email
};
//将用户数据存储在AspNetUsers数据库表中
var result = await userManager.CreateAsync(user, model.Password);
//如果成功创建用户,则使用登录服务登录用户信息
//并重定向到HomeController的Index操作方法中(跳转到主页面)
if (result.Succeeded)
{
await signInManager.SignInAsync(user, isPersistent:false);
return RedirectToAction("index","home");
}
//如果有任何错误,将它们添加到ModelState对象中
//将由验证摘要标记助手显示到视图中
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
return View(model);
}
}
}
3.启动项目之后发现
- 密码验证机制太复杂了
- 它是英文的,对于我们来说支持不是太友好
三.ASP.NET Core Identity密码默认设置
1.在Startup中添加
点击查看代码
services.Configure<IdentityOptions>(options =>
{
options.Password.RequiredLength = 6;
options.Password.RequiredUniqueChars = 3;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireLowercase = false;
options.Password.RequireUppercase = false;
options.SignIn.RequireConfirmedEmail = true;
//通过自定义的CustomEmailConfirmation名称来覆盖旧有token名称,是它与AddTokenProvider<CustomEmailConfirmationTokenProvider<ApplicationUser>>("CustomEmailConfirmation")关联在一起
options.Tokens.EmailConfirmationTokenProvider = "CustomEmailConfirmation";
options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(15);
});
2.修改中文提示的错误信息
在根目录下 添加CustomIdentityErrorDescriber类,继承于IdentityErrorDescriber
点击查看代码
using Microsoft.AspNetCore.Identity;
namespace MockSchoolManageMent
{
public class CustomIdentityErrorDescriber : IdentityErrorDescriber
{
public override IdentityError DefaultError()
{
return new IdentityError { Code = nameof(DefaultError), Description = $"发生了未知的故障。" };
}
public override IdentityError ConcurrencyFailure()
{
return new IdentityError { Code = nameof(ConcurrencyFailure), Description = "乐观并发失败,对象已被修改。" };
}
public override IdentityError PasswordMismatch()
{
return new IdentityError { Code = nameof(PasswordMismatch), Description = "密码错误" };
}
public override IdentityError InvalidToken()
{
return new IdentityError { Code = nameof(InvalidToken), Description = "无效的令牌." };
}
public override IdentityError LoginAlreadyAssociated()
{
return new IdentityError { Code = nameof(LoginAlreadyAssociated), Description = "具有此登录的用户已经存在." };
}
public override IdentityError InvalidUserName(string userName)
{
return new IdentityError { Code = nameof(InvalidUserName), Description = $"用户名'{userName}'无效,只能包含字母或数字." };
}
public override IdentityError InvalidEmail(string email)
{
return new IdentityError { Code = nameof(InvalidEmail), Description = $"邮箱 '{email}' 无效." };
}
public override IdentityError DuplicateUserName(string userName)
{
return new IdentityError { Code = nameof(DuplicateUserName), Description = $"用户名 '{userName}' 已被使用." };
}
public override IdentityError DuplicateEmail(string email)
{
return new IdentityError { Code = nameof(DuplicateEmail), Description = $"邮箱 '{email}' 已被使用." };
}
public override IdentityError InvalidRoleName(string role)
{
return new IdentityError { Code = nameof(InvalidRoleName), Description = $"角色名 '{role}' 无效." };
}
public override IdentityError DuplicateRoleName(string role)
{
return new IdentityError { Code = nameof(DuplicateRoleName), Description = $"角色名 '{role}' 已被使用." };
}
public override IdentityError UserAlreadyHasPassword()
{
return new IdentityError { Code = nameof(UserAlreadyHasPassword), Description = "该用户已设置了密码." };
}
public override IdentityError UserLockoutNotEnabled()
{
return new IdentityError { Code = nameof(UserLockoutNotEnabled), Description = "此用户未启用锁定." };
}
public override IdentityError UserAlreadyInRole(string role)
{
return new IdentityError { Code = nameof(UserAlreadyInRole), Description = $"用户已关联角色 '{role}'." };
}
public override IdentityError UserNotInRole(string role)
{
return new IdentityError { Code = nameof(UserNotInRole), Description = $"用户未关联角色 '{role}'." };
}
public override IdentityError PasswordTooShort(int length)
{
return new IdentityError { Code = nameof(PasswordTooShort), Description = $"密码必须至少是{length}字符." };
}
public override IdentityError PasswordRequiresNonAlphanumeric()
{
return new IdentityError
{
Code = nameof(PasswordRequiresNonAlphanumeric),
Description = "密码必须至少有一个非字母数字字符."
};
}
public override IdentityError PasswordRequiresDigit()
{
return new IdentityError { Code = nameof(PasswordRequiresDigit), Description = $"密码必须至少有一个数字('0'-'9')." };
}
public override IdentityError PasswordRequiresUniqueChars(int uniqueChars)
{
return new IdentityError { Code = nameof(PasswordRequiresUniqueChars), Description = $"密码必须使用至少不同的{uniqueChars}字符。" };
}
public override IdentityError PasswordRequiresLower()
{
return new IdentityError { Code = nameof(PasswordRequiresLower), Description = "密码必须至少有一个小写字母('a'-'z')." };
}
public override IdentityError PasswordRequiresUpper()
{
return new IdentityError { Code = nameof(PasswordRequiresUpper), Description = "密码必须至少有一个大写字母('A'-'Z')." };
}
}
}
3.添加修改自定义错误信息显示方法
在startup类中的ConfigureServices()方法中,在AddIdentity()服务中使用AddErrorDescriber()方法覆盖默认的错误提示内容
services.AddIdentity<IdentityUser, IdentityRole>().AddErrorDescriber<CustomIdentityErrorDescriber>().AddEntityFrameworkStores<AppDbContext>();