(十一)React Ant Design Pro + .Net5 WebApi:後端環境搭建-IdentityServer4(三)持久化
阿新 • • 發佈:2022-04-14
一、前言
IdentityServer配合EFCore持久化,框架已經為我們準備了兩個上下文:
-
ConfigurationDbContext
:配置資料(資源、客戶端、身份等) -
PersistedGrantDbContext
:操作資料(授權碼、訪問令牌、重新整理令牌等)
使用者持久化可以自定義一套邏輯,But,我們直接用微軟的Identity,再新建一個使用者上下文:
-
ApplicationDbContext
:使用者資料(使用者、角色等)
二、持久化
1、新建認證服務
新建一個MVC工程,目錄結構跟上篇記憶體化大致一樣,IdentityServer4.Persistence
安裝所需包:
IdentityServer4
IdentityServer4.EntityFramework
Microsoft.EntityFrameworkCore.Tools
-
Npgsql.EntityFrameworkCore.PostgreSQL
(PostgreSQL) -
IdentityServer4.AspNetIdentity
(IdentityServer4支援微軟Indentity) -
Microsoft.AspNetCore.Identity.EntityFrameworkCore
(Identity支援EF)
2、新建使用者上下文
//IdentityUser實際肯定是需要拓展的,還有一些自定義等功能,Demo這兒就不費勁了,隨後要挪到正式的環境,用到再細說 public class ApplicationDbContext : IdentityDbContext<IdentityUser> { public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); } }
3、Startup.cs 配置持久化
public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); //讀取資料庫連線 var connectionString = Configuration.GetSection("DB").Value; if (connectionString == "") { throw new Exception("資料庫配置異常"); } /**********************************IdentityServer4持久化配置**********************************/ var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name; //新增使用者資料上下文 ApplicationDbContext services.AddDbContext<ApplicationDbContext>(options => options.UseNpgsql(connectionString)); services.AddIdentity<IdentityUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders(); //新增配置資料上下文 ConfigurationDbContext、操作資料上下文 PersistedGrantDbContext、使用者持久化 var builder = services.AddIdentityServer() .AddConfigurationStore(options => { options.ConfigureDbContext = builder => { builder.UseNpgsql(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly)); }; }) .AddOperationalStore(options => { options.ConfigureDbContext = builder => { builder.UseNpgsql(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly)); }; //token配置 options.EnableTokenCleanup = true; options.TokenCleanupInterval = 30; }) .AddAspNetIdentity<IdentityUser>() .AddDeveloperSigningCredential(); }
4、遷移到資料庫
程式包管理器控制檯,依次輸入一下命令回車:
add-migration InitialPersisted -c PersistedGrantDbContext -o Migrations/Persisted
update-database -Context PersistedGrantDbContext
add-migration InitialConfiguration -c ConfigurationDbContext -o Migrations/Configuration
update-database -Context ConfigurationDbContext
add-migration InitialApplication -c ApplicationDbContext -o Migrations/Application
update-database -Context ApplicationDbContext
資料庫表、ER關係圖
5、初始化種子資料
新建SeedData.cs
,初始化種子資料,使用之前在InMemoryConfig.cs
配置好的記憶體資料
public class SeedData
{
public static void InitData(IApplicationBuilder serviceProvider)
{
using (var scope = serviceProvider.ApplicationServices.CreateScope())
{
//初始化種子資料:配置、資源、客戶端等
scope.ServiceProvider.GetRequiredService<PersistedGrantDbContext>().Database.Migrate();
{
var context = scope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
context.Database.Migrate();
InitSeedData(context);
}
//初始化種子資料:使用者
{
var context = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
context.Database.Migrate();
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<IdentityUser>>();
foreach (var user in InMemoryConfig.GetTestUser())
{
var find = userManager.FindByNameAsync(user.Username).Result;
if (find == null)
{
IdentityUser u = new IdentityUser() { UserName = user.Username };
//密碼格式嚴格(至少一個非字母字元、至少一位0-9數字)
var ret = userManager.CreateAsync(u, "WinterSir123!").Result;
if (ret.Succeeded)
{
userManager.AddClaimsAsync(u, user.Claims);
}
}
}
}
}
}
private static void InitSeedData(ConfigurationDbContext context)
{
if (!context.Clients.Any())
{
foreach (var client in InMemoryConfig.GetClients())
{
context.Clients.Add(client.ToEntity());
}
context.SaveChanges();
}
if (!context.IdentityResources.Any())
{
foreach (var resource in InMemoryConfig.IdentityResources)
{
context.IdentityResources.Add(resource.ToEntity());
}
context.SaveChanges();
}
if (!context.ApiResources.Any())
{
foreach (var resource in InMemoryConfig.GetApiResources())
{
context.ApiResources.Add(resource.ToEntity());
}
context.SaveChanges();
}
if (!context.ApiScopes.Any())
{
foreach (var resource in InMemoryConfig.GetApiScopes())
{
context.ApiScopes.Add(resource.ToEntity());
}
context.SaveChanges();
}
}
}
呼叫程式碼放這裡,認證服務啟動時初始化,之前記憶體模式配置持久化到資料庫
6、修改登入、登出程式碼**
其實我也沒弄白為啥要改登入那塊,一般情況都是用框架原生提供的方法才對,百度谷歌不得其解,大佬可以指點一下
三、效果圖
**可以看到我們必須要用新密碼WinterSir123!才能登入,匹配是已經持久化資料庫的資訊
四、前任栽樹,後人乘涼
https://zhuanlan.zhihu.com/p/352497277