我们之前都是用Identityserver4的测试类把数据添加到内存了,目的是为了测试方便,
现在我们把用户的信息利用ASP.NET Identity的方式持久化到数据库中。
1、引入Identityserver4.AspNetIdentity,然后新建一个ApplicationUser,ApplicationRole的类
public class ApplicationUser : IdentityUser<string>//不加int的话是默认主键为guid
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public override string Id { get; set; }
}
public class ApplicationUserRoles : IdentityRole<string>
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Key]
public override string Id { get; set; }
}
2、替换服务端stratup中 .AddTestUsers(Config.GetUsers().ToList()) 换成
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddDbContext<ApplicationDbContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("Conn"));
});
//配置Identity
services.AddIdentity<ApplicationUser, ApplicationUserRoles>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
//修改Identity密码强度设置配置
services.Configure<IdentityOptions>(options =>
{
options.Password.RequireLowercase = false; //需要小写
options.Password.RequireNonAlphanumeric = false; //需要字母
options.Password.RequireUppercase = false; //需要大写
options.Password.RequiredLength = 6;
});
services.AddIdentityServer().AddDeveloperSigningCredential()
.AddInMemoryApiResources(Config.GetApiResources())
.AddInMemoryApiScopes(Config.GetScopes())
.AddInMemoryClients(Config.GetClients())
// .AddTestUsers(Config.GetUsers().ToList())
.AddAspNetIdentity<ApplicationUser>()
.AddInMemoryIdentityResources(Config.GetIdentityResources());
services.AddControllersWithViews();
}
3、替换登录逻辑,将Testuser的登录逻辑换成Identity的登录逻辑
public class AccountController : Controller { // private readonly TestUserStore _testUserStore; private readonly UserManager<ApplicationUser> _userManager; private readonly SignInManager<ApplicationUser> _signinManager; private readonly IIdentityServerInteractionService _InteractionService; public AccountController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signinManager, IIdentityServerInteractionService identityServerInteractionService) { _userManager = userManager; _signinManager = signinManager; _InteractionService = identityServerInteractionService; } //public AccountController( TestUserStore testUserStore) //{ // _testUserStore = testUserStore; //} public IActionResult Index() { return View(); } public IActionResult Login(string returnUrl = "/Home/Index") { ViewData["Rurl"] = returnUrl; return View(); } /// <summary> /// post 登录请求 /// </summary> /// <returns></returns> [HttpPost] public async Task<IActionResult> Login(LoginInputModel model) { if (!ModelState.IsValid) { return View(); } var user = await _userManager.FindByNameAsync(model.Name); // var user = _testUserStore.FindByUsername(model.Username); if (user == null) { return View(); } //if (_testUserStore.ValidateCredentials(model.Username, model.Password)) if (await _userManager.CheckPasswordAsync(user, model.Password)) { var props = new AuthenticationProperties { IsPersistent = false, //是否记住。默认不记住。可以根据前端的传值改。 ExpiresUtc = DateTimeOffset.UtcNow.Add(TimeSpan.FromMinutes(1)) }; // await HttpContext.SignInAsync(user.SubjectId, user.Username, props); //await AuthenticationManagerExtensions.SignInAsync( // HttpContext, // new IdentityServerUser(user.SubjectId), // props // ); await _signinManager.SignInAsync(user, props); if (!string.IsNullOrEmpty(model.ReturnUrl)) //if (_InteractionService.IsValidReturnUrl(model.ReturnUrl)) { return Redirect(model.ReturnUrl); } else { return Redirect("~/"); } } return View(); } /// <summary> /// 退出登录 /// </summary> /// <returns></returns> public async Task<IActionResult> Logout() { await _signinManager.SignOutAsync(); return Redirect("/Login"); } }
4、新增一个data文件夹用于存放初始化 数据库的相关类
public class ApplicationDbContext :IdentityDbContext<ApplicationUser,ApplicationUserRoles,string> { public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { } }
种子文件:数据库没有数据时,运行的时候给添加一个默认账户
public class ApplicationDbContextSeed { private UserManager<ApplicationUser> _userManager; private RoleManager<ApplicationUserRoles> _roleManager; public async Task SeedAsync(ApplicationDbContext context, IServiceProvider services) { if (!context.Roles.Any()) { var role = new ApplicationUserRoles() { Id="111", Name = "Administrators", NormalizedName = "Administrators" }; _roleManager = services.GetRequiredService<RoleManager<ApplicationUserRoles>>(); var result = await _roleManager.CreateAsync(role); if (!result.Succeeded) { throw new Exception("初始默认角色失败:"+result.Errors.SelectMany(e=>e.Description)); } } if (!context.Users.Any()) { _userManager = services.GetRequiredService<UserManager<ApplicationUser>>(); var defaultUser = new ApplicationUser { Id="111111", UserName = "Administrator", Email = "11111111@qq.com", NormalizedUserName = "admin", SecurityStamp = "admin", }; var result = await _userManager.CreateAsync(defaultUser, "123456"); await _userManager.AddToRoleAsync(defaultUser, "Administrators"); if (!result.Succeeded) { throw new Exception("初始默认用户失败:" + result.Errors.SelectMany(e => e.Description)); } } } }
在程序开始运行前执行种子文件
public static class WebHostMigrationExtensions { public static IHost MigrateDbContext<TContext>(this IHost host, Action<TContext, IServiceProvider> sedder) where TContext : DbContext { using (var scope = host.Services.CreateScope()) {//只在本区间内有效 var services = scope.ServiceProvider; var logger = services.GetRequiredService<ILogger<TContext>>(); var context = services.GetService<TContext>(); try { context.Database.Migrate(); sedder(context, services); logger.LogInformation($"执行DBContext {typeof(TContext).Name} seed执行成功"); } catch (Exception ex) { logger.LogError(ex, $"执行DBContext {typeof(TContext).Name} seed方法失败"); } } return host; } }
在program中加入启动时运行种子文件
public static void Main(string[] args) { CreateHostBuilder(args).Build() .MigrateDbContext<ApplicationDbContext>((context, services) => { new ApplicationDbContextSeed().SeedAsync(context, services).Wait(); }) .Run(); }
5、数据库迁移
1、 Add-Migration 2、 Update-Database
运行完成后生成的数据库表
至此全部配置完毕,运行程序,数据库会初始化一条数据。
用该用户名和密码登录成功。