在前面的篇章介紹中,一些基礎配置如API資源、客戶端資源等數據以及使用過程當中發放的令牌等操做數據,咱們都是經過將操做數據和配置數據存儲在內存中進行實現的,而在實際開發生產中,咱們須要考慮如何處理數據持久化呢?html
這時IdentityServer4具備良好的擴展性,其中一個可擴展點是用於IdentityServer所需數據的存儲機制,進行持久化操做。git
下面將如何配置IdentityServer以使用EntityFramework(EF)做爲此數據的存儲機制把這些數據存儲到Sql Server數據庫, 這樣更符合咱們實際生產環境的需求。github
在咱們的 IdentityServer4中官方定義的兩個上下文,是有兩種類型的數據須要持久化到數據庫中:sql
一、配置數據(資源、客戶端、身份);//這裏是對應配置上下文
ConfigurationDbContext
shell二、IdentityServer在使用時產生的 操做數據(令牌,代碼和用戶的受權信息consents);//這裏是對應操做上下文
PersistedGrantDbContext
數據庫
這兩個上下文以及對應的數據模型,已經被 IdentityServer4 官方給封裝好了, 咱們不須要作額外的操做,直接進行遷移便可使用。json
ConfigurationDbContext
(IdentityServer configuration data) —— 負責數據庫中對客戶端、資源和 CORS 設置的配置存儲;網絡
若是須要從 EF 支持的數據庫加載客戶端、標識資源、API 資源或 CORS 數據 (而不是使用內存中配置), 則可使用配置存儲。此支持提供 IClientStore
、IResura Store
和 ICorsPolicyService
擴展性點的實現。這些實現使用名爲 ConfigurationDbContext
的 dbcontext 派生類對數據庫中的表進行建模。antd
PersistedGrantDbContext
(IdentityServer operational data.) -—— 負責存儲贊成、受權代碼、刷新令牌和引用令牌;app
若是須要從 EF 支持的數據庫 (而不是默認的內存數據庫) 加載受權授予、贊成和令牌 (刷新和引用), 則可使用操做存儲。此支持提供了 IPersistedGrantStore
擴展點的實現。實現使用名爲 PersistedGrantDbContext
的 dbcontext 派生類對數據庫中的表進行建模。
創建一個MVC的Asp.Net Core項目 ,使用MVC模板
IdentityServer4.EntityFramework
以及EF相關包
1.IdentityServer4 2.IdentityServer4.AspNetIdentity 3.IdentityServer4.EntityFramework
由於本文中使用的是SqlServer
數據庫,因此須要安裝對應的EF程序包對數據庫的支持。
Microsoft.EntityFrameworkCore.SqlServer
appsettings.json
"ConnectionStrings": { "DataContext": "data source=.;initial catalog=Yuan.Idp;user id=sa;password=123456;", }
配置鏈接數據庫
var connectionString = Configuration.GetConnectionString("DataContext"); if (connectionString == "") { throw new Exception("數據庫配置異常"); }
2.配置數據庫服務
在startup.cs中ConfigureServices方法添加以下代碼:
public void ConfigureServices(IServiceCollection services) { services.AddControllersWithViews(); var connectionString = Configuration.GetConnectionString("DataContext"); if (connectionString == "") { throw new Exception("數據庫配置異常"); } var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name; // in DB config var builder = services.AddIdentityServer(options => { options.Events.RaiseErrorEvents = true; options.Events.RaiseInformationEvents = true; options.Events.RaiseFailureEvents = true; options.Events.RaiseSuccessEvents = true; }).AddConfigurationStore(options => //添加配置數據(ConfigurationDbContext上下文用戶配置數據) { options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly)); }).AddOperationalStore(options => //添加操做數據(PersistedGrantDbContext上下文 臨時數據(如受權和刷新令牌)) { options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly)); // 自動清理 token ,可選 options.EnableTokenCleanup = true; // 自動清理 token ,可選 options.TokenCleanupInterval = 30; }).AddTestUsers(TestUsers.Users); // not recommended for production - you need to store your key material somewhere secure builder.AddDeveloperSigningCredential(); services.ConfigureNonBreakingSameSiteCookies(); }
方法一:
須要添加EF工具,安裝Microsoft.EntityFrameworkCore.Tools
, 進行遷移
一、add-migration InitialIdentityServerPersistedGrantDbMigration -c PersistedGrantDbContext -o Data/Migrations/PersistedGrantDb 二、add-migration InitialIdentityServerConfigurationDbMigration -c ConfigurationDbContext -o Data/Migrations/ConfigurationDb 三、update-database -Context PersistedGrantDbContext 四、update-database -Context ConfigurationDbContext
方法二:
判斷是否支持命令行遷移,你能夠在項目所在的目錄下打開一個命令 Power shell 並運行命令 dotnet ef, 它應該是這樣的:
dotnet ef 沒法執行,由於找不到指定的命令或文件
從 3.0 起,EF Core 命令列工具 (dotnet ef) 不在 .NET Core SDK 裏面,需另裝。命令以下:
dotnet tool install --global dotnet-ef
要建立遷移,請在IdentityServer項目目錄中打開命令提示符。 在命令提示符下運行這兩個命令:
1. dotnet ef migrations add InitialIdentityServerPersistedGrantDbMigration -c PersistedGrantDbContext -o Data/Migrations/PersistedGrantDb 2. dotnet ef migrations add InitialIdentityServerConfigurationDbMigration -c ConfigurationDbContext -o Data/Migrations/ConfigurationDb #生成 1. update-database -c PersistedGrantDbContext 2. update-database -c ConfigurationDbContext
(圖片來自網絡)
在以前的篇章中,咱們是定義的內存配置數據實現的操做,而在本篇中,咱們進行數據持久化操做,能夠將以前內存的數據做爲種子處理遷移到建立的數據庫中進行初始化操做。
參考文章: 用戶數據遷移
建立SeedData.cs文件,用於初始化基礎數據:
public class SeedData { public static void EnsureSeedData(IServiceProvider serviceProvider) { Console.WriteLine("Seeding database..."); using (var scope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope()) { scope.ServiceProvider.GetService<PersistedGrantDbContext>().Database.Migrate(); var context = scope.ServiceProvider.GetRequiredService<ConfigurationDbContext>(); context.Database.Migrate(); EnsureSeedData(context); } Console.WriteLine("Done seeding database."); Console.WriteLine(); } private static void EnsureSeedData(ConfigurationDbContext context) { if (!context.Clients.Any()) { Console.WriteLine("Clients 正在初始化"); foreach (var client in Config.GetClients) { context.Clients.Add(client.ToEntity()); } context.SaveChanges(); } if (!context.IdentityResources.Any()) { Console.WriteLine("IdentityResources 正在初始化"); foreach (var resource in Config.GetIdentityResources) { context.IdentityResources.Add(resource.ToEntity()); } context.SaveChanges(); } if (!context.ApiResources.Any()) { Console.WriteLine("ApiResources 正在初始化"); foreach (var resource in Config.GetApiResources) { context.ApiResources.Add(resource.ToEntity()); } context.SaveChanges(); } if (!context.ApiScopes.Any()) { Console.WriteLine("ApiScopes 正在初始化"); foreach (var resource in Config.GetApiScopes) { context.ApiScopes.Add(resource.ToEntity()); } context.SaveChanges(); } } }
配置內容能夠查看以前篇章內容文件Config.cs 或者項目地址.
而後咱們能夠從主入口Main
方法調用它:
public static void Main(string[] args) { var seed = args.Contains("/seed"); if (seed) { args = args.Except(new[] { "/seed" }).ToArray(); } var host = CreateHostBuilder(args).Build(); if (seed) { SeedData.EnsureSeedData(host.Services); } host.Run(); }
輸入 dotnet run /seed
上面咱們說到了的兩個上下文,若是咱們直接經過執行遷移命令是會報錯的,好比咱們直接遷移 PersistedGrantDbContext 上下文:
由於遷移的目標不匹配,須要更改遷移程序集,如
options.UseSqlServer(connection, b => b.MigrationsAssembly("Ids4.EFCore"))
因此,就須要在項目中配置對應的服務,咱們在 startup.cs 啓動文件中,配置服務 ConfigureService ,配置 EF 操做數據庫.
解決方法 : 可參考上面的實踐部分中的數據庫上下文.
獲取數據庫鏈接字符串
配置數據庫服務
由於找不到指定的命令或文件
從 3.0 起,EF Core 命令列工具 (dotnet ef) 不在 .NET Core SDK 裏面,需另裝。命令以下:
dotnet tool install --global dotnet-ef