此前我們已經使用EFCore將IdentityServer4相關配置寫入SqlServer,但是用戶數據還是寫死的TestUser,本篇將集成
ASP.NET Core Identity
,將用戶數據保存到SqlServer中,當然,您也可以使用自建的用戶數據庫。
開始前先安裝必要的nuget包
Install-Package Microsoft.AspNetCore.Identity.EntityFrameworkCore -Version 3.1.1
Install-Package Microsoft.EntityFrameworkCore.SqlServer -Version 3.1.1
添加上下文
public class AspNetAccountDbContext : IdentityDbContext<ApplicationUser>
{
public AspNetAccountDbContext(DbContextOptions<AspNetAccountDbContext> options) : base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
}
}
向容器中添加服務
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<AspNetAccountDbContext>(options =>
{
options.UseSqlServer(Configuration.GetConnectionString("DefaultAspNetAccountConnection"));
});
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<AspNetAccountDbContext>()
.AddDefaultTokenProviders();
services.Configure<IdentityOptions>(options =>
{
// 密碼複雜度配置
options.Password.RequireDigit = true;
options.Password.RequiredLength = 6;
options.Password.RequiredUniqueChars = 1;
options.Password.RequireLowercase = false;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
});
// 爲了代碼簡單一點,後面的配置省略,可參考前文
}
登錄控制器的修改
刪除原先的TestUserStore,使用ASP.NET Core Identity進行操作
public class AccountController : Controller
{
private UserManager<ApplicationUser> _userManager;
private SignInManager<ApplicationUser> _signInManager;
private IIdentityServerInteractionService _interaction;
public AccountController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager, IIdentityServerInteractionService interaction)
{
_userManager = userManager;
_signInManager = signInManager;
_interaction = interaction;
}
public IActionResult Login(string returnUrl)
{
ViewData["ReturnUrl"] = returnUrl;
return View();
}
[HttpPost]
public async Task<IActionResult> Login(LoginViewModel loginViewModel, string returnUrl)
{
if (!ModelState.IsValid)
{
return View();
}
var user = await _userManager.FindByEmailAsync(loginViewModel.Email);
if (user == null)
{
ModelState.AddModelError(nameof(loginViewModel.Email), $"Email {loginViewModel.Email} not exists");
}
else
{
if (await _userManager.CheckPasswordAsync(user, loginViewModel.Password))
{
AuthenticationProperties props = null;
if (loginViewModel.RememberMe)
{
props = new AuthenticationProperties
{
IsPersistent = true,
ExpiresUtc = DateTimeOffset.UtcNow.Add(TimeSpan.FromMinutes(30))
};
}
await _signInManager.SignInAsync(user, props);
if (_interaction.IsValidReturnUrl(returnUrl))
{
return Redirect(returnUrl);
}
return Redirect("~/");
}
ModelState.AddModelError(nameof(loginViewModel.Password), "Wrong password");
}
return View(loginViewModel);
}
}
數據遷移
執行命令
add-migration InitialAspNetAccountDbMigration -c AspNetAccountDbContext -o Data/Migrations/Application/AspNetAccountDb
可以看到成功添加了遷移代碼
執行命令生成數據庫
update-database -c AspNetAccountDbContext
成功生成
播種默認用戶數據
public class SeedData
{
public static void EnsureSeedAspNetAccountData(string connectionString)
{
var services = new ServiceCollection();
services.AddLogging();
services.AddDbContext<AspNetAccountDbContext>(options =>
{
options.UseSqlServer(connectionString);
});
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<AspNetAccountDbContext>()
.AddDefaultTokenProviders();
services.Configure<IdentityOptions>(options =>
{
options.Password.RequireDigit = true;
options.Password.RequiredLength = 6;
options.Password.RequiredUniqueChars = 1;
options.Password.RequireLowercase = false;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
});
using (var serviceProvider = services.BuildServiceProvider())
{
using (var scope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
var context = scope.ServiceProvider.GetService<AspNetAccountDbContext>();
context.Database.Migrate();
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<ApplicationUser>>();
var zhangsan = userManager.FindByNameAsync("zhangsan").Result;
if (zhangsan == null)
{
zhangsan = new ApplicationUser
{
UserName = "zhangsan",
Email = "[email protected]"
};
var result = userManager.CreateAsync(zhangsan, "123456").Result;
if (!result.Succeeded)
{
throw new Exception(result.Errors.First().Description);
}
result = userManager.AddClaimsAsync(zhangsan, new Claim[] {
new Claim(JwtClaimTypes.Name, "張三"),
new Claim(JwtClaimTypes.GivenName, "三"),
new Claim(JwtClaimTypes.FamilyName, "張"),
new Claim(JwtClaimTypes.Email, "[email protected]"),
new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean),
new Claim(JwtClaimTypes.WebSite, "http://zhangsan.com"),
new Claim(JwtClaimTypes.Address, @"{ '城市': '杭州', '郵政編碼': '310000' }",
IdentityServer4.IdentityServerConstants.ClaimValueTypes.Json)
}).Result;
if (!result.Succeeded)
{
throw new Exception(result.Errors.First().Description);
}
}
// 爲了代碼簡單一點,刪除其他用戶數據
}
}
}
}
當我們成功運行程序後,查看數據庫,可以看到種子數據已經插入
更多
可訪問GitHub查看源碼