IdentityServer4系列 | 支持數據持久化

1、前言

在前面的篇章介紹中,一些基礎配置如API資源、客戶端資源等數據以及使用過程當中發放的令牌等操做數據,咱們都是經過將操做數據和配置數據存儲在內存中進行實現的,而在實際開發生產中,咱們須要考慮如何處理數據持久化呢?html

這時IdentityServer4具備良好的擴展性,其中一個可擴展點是用於IdentityServer所需數據的存儲機制,進行持久化操做。git

下面將如何配置IdentityServer以使用EntityFramework(EF)做爲此數據的存儲機制把這些數據存儲到Sql Server數據庫, 這樣更符合咱們實際生產環境的需求。github

2、初識

在咱們的 IdentityServer4中官方定義的兩個上下文,是有兩種類型的數據須要持久化到數據庫中:sql

一、配置數據(資源、客戶端、身份);//這裏是對應配置上下文 ConfigurationDbContextshell

二、IdentityServer在使用時產生的 操做數據(令牌,代碼和用戶的受權信息consents);//這裏是對應操做上下文 PersistedGrantDbContext數據庫

這兩個上下文以及對應的數據模型,已經被 IdentityServer4 官方給封裝好了, 咱們不須要作額外的操做,直接進行遷移便可使用。json

2.1 ConfigurationDb

ConfigurationDbContext (IdentityServer configuration data) —— 負責數據庫中對客戶端、資源和 CORS 設置的配置存儲;網絡

若是須要從 EF 支持的數據庫加載客戶端、標識資源、API 資源或 CORS 數據 (而不是使用內存中配置), 則可使用配置存儲。此支持提供 IClientStoreIResura StoreICorsPolicyService 擴展性點的實現。這些實現使用名爲 ConfigurationDbContextdbcontext 派生類對數據庫中的表進行建模。antd

2.2 PersistedGrantDb

PersistedGrantDbContext (IdentityServer operational data.) -—— 負責存儲贊成、受權代碼、刷新令牌和引用令牌;app

若是須要從 EF 支持的數據庫 (而不是默認的內存數據庫) 加載受權授予、贊成和令牌 (刷新和引用), 則可使用操做存儲。此支持提供了 IPersistedGrantStore 擴展點的實現。實現使用名爲 PersistedGrantDbContextdbcontext 派生類對數據庫中的表進行建模。

3、實踐

3.1 新建站點

創建一個MVC的Asp.Net Core項目 ,使用MVC模板

3.2 Nuget包

IdentityServer4.EntityFramework以及EF相關包

1.IdentityServer4
2.IdentityServer4.AspNetIdentity
3.IdentityServer4.EntityFramework

由於本文中使用的是SqlServer數據庫,因此須要安裝對應的EF程序包對數據庫的支持。

Microsoft.EntityFrameworkCore.SqlServer

3.3 數據庫上下文

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();
        }

3.4 遷移數據

3.4.1 控制檯遷移

方法一:

須要添加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

3.4.2 在命令窗口

方法二:

判斷是否支持命令行遷移,你能夠在項目所在的目錄下打開一個命令 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

3.5 顯示數據庫

(圖片來自網絡)

3.6 初始化數據庫

在以前的篇章中,咱們是定義的內存配置數據實現的操做,而在本篇中,咱們進行數據持久化操做,能夠將以前內存的數據做爲種子處理遷移到建立的數據庫中進行初始化操做。

參考文章: 用戶數據遷移

3.6.1 建立文件

建立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 或者項目地址.

3.6.2 調用方法

而後咱們能夠從主入口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();
        }

3.6.3 程序運行

輸入 dotnet run /seed 

3.6.4 效果

4、問題

4.1 提示找不到上下文

上面咱們說到了的兩個上下文,若是咱們直接經過執行遷移命令是會報錯的,好比咱們直接遷移 PersistedGrantDbContext 上下文:

由於遷移的目標不匹配,須要更改遷移程序集,如

options.UseSqlServer(connection, b => b.MigrationsAssembly("Ids4.EFCore"))

因此,就須要在項目中配置對應的服務,咱們在 startup.cs 啓動文件中,配置服務 ConfigureService ,配置 EF 操做數據庫.

解決方法 : 可參考上面的實踐部分中的數據庫上下文.

  1. 獲取數據庫鏈接字符串

  2. 配置數據庫服務

4.2 dotnet ef 沒法執行

由於找不到指定的命令或文件

從 3.0 起,EF Core 命令列工具 (dotnet ef) 不在 .NET Core SDK 裏面,需另裝。命令以下:

dotnet tool install --global dotnet-ef

5、總結

  1. 簡單介紹了IdentityServer4持久化存儲機制相關配置和操做數據,實現了數據遷移,及應用程序的實踐。
  2. 本篇未對用戶進行持久化操做存儲說明,由於IdentityServer4本就支持了接入其餘認證方式,因此本身根據須要進行合理擴展的,好比咱們可使用 Asp.Net Core 自帶的 Identity 身份認證機制來實現擴展,固然,你也能夠本身定義相應的操做,在後續篇章中會進行說明介紹。
  3. 若是有不對的或不理解的地方,但願你們能夠多多指正,提出問題,一塊兒討論,不斷學習,共同進步。
  4. 項目地址

6、附加

EF支持持久化配置和操做數據

相關文章
相關標籤/搜索