IdentityServer4(八)使用EntityFramework Core對數據進行持久化

上幾篇,我們創建了客戶端,scope,啓動時,IdentityServer把這些配置數據加載至內存,但是,如果我們想要更改配置,就必須停掉IdentityServer,然後重新啓動。且IdentityServe在r運行過程中還會生成臨時數據,如授權碼、是否同意的按鈕選擇、以及refresh token。默認情況下,這些也存儲在內存中。

將以上這些數據存儲在數據庫中進行數據持久化,方便重啓跨多個IdentityServer實例,這個持久化,我們可以使用IdentityServer4 Entity Framework

除了手動配置EF支持之外,還有一個IdentityServer模板可以使用,dotnet new is4ef創建一個支持EF的新項目。

IdentityServer4.EntityFrameworknuget包實現了所需的存儲和服務,主要使用以下兩個DbContexts:

  • ConfigurationDbContext - 作用於註冊數據,如客戶端,資源,scope等等

  • PersistedGrantDbContext - 作用於臨時操作數據,如授權碼,refresh tokens

這些context適用於任何ef core兼容的關係型數據庫,sqlserver,mysql。

可以在

  • IdentityServer4.EntityFramework.Storage包中找到contextentitiesIdentityServer4 stores

  • IdentityServer4.EntityFramework包括了註冊的擴展方法,且包括了IdentityServer4.EntityFramework.Storage

1.添加nuget引用

cd .\IdentityServer\
dotnet add package IdentityServer4.EntityFramework

2.添加對mysql的支持

dotnet add package MySql.Data.EntityFrameworkCore

3.數據遷移

IdentityServer4.EntityFramework.Storage包存在包含映射自IdentityServer模型的實體類,隨着IdentityServer的模型的更改,IdentityServer4.EntityFramework.Storage中的實體類也將更改,所以需要使用者隨着時間的推移,升級使用這個包,這個過程,需要負責在數據庫架構以及在實體類更改時,對該數據庫架構進行必要的更改。最好的方式就是使用EF數據遷移(EF migrations)

這裏官方只提供了針對sqlserver的sql腳本,可以看一下,做個瞭解。

4.重新配置存儲

Startup.cs

using Microsoft.EntityFrameworkCore;
using System.Reflection; //這裏用到了反射

var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

//3308爲宿主機端口,映射docker mysql容器默認端口3306
const string connectionString = @"Persist Security Info=False;database=IdentityServer4;server=localhost;port=3308;Connect Timeout=30;user id=root; pwd=123456";

services.AddIdentityServer()
    .AddTestUsers(TestUsers.Users)
    .AddConfigurationStore(options =>
                {
                    options.ConfigureDbContext = b => b.UseMySQL(connectionString,
                        sql => sql.MigrationsAssembly(migrationsAssembly));
                })
                .AddOperationalStore(options =>
                {
                    options.ConfigureDbContext = b => b.UseMySQL(connectionString,
                        sql => sql.MigrationsAssembly(migrationsAssembly));
                });

因爲我們在IdentityServer.csproj中使用EF遷移,所以通過對MigrationsAssembly的調用來告訴Entity Framework 的宿主項目(IdentityServer.csproj)將包含遷移代碼(the migrations code)。這是必要的,因爲宿主項目(IdentityServer.csproj)與包含DbContext類的項目,兩者是位於不同的程序集中(IdentityServer4.EntityFramework.Storage)。

5.創建遷移

一旦將IdentityServer配置爲使用 Entity Framework Core,我們將需要生成一些遷移-migrations。

Entity Framework Core CLI

Microsoft.EntityFrameworkCore.Design nuget包

#安裝ef core 工具
dotnet tool install --global dotnet-ef
dotnet add package Microsoft.EntityFrameworkCore.Design

#cd到IdentityServer項目目錄
dotnet ef migrations add InitialIdentityServerPersistedGrantDbMigration -c PersistedGrantDbContext -o Data/Migrations/IdentityServer/PersistedGrantDb


dotnet ef migrations add InitialIdentityServerConfigurationDbMigration -c ConfigurationDbContext -o Data/Migrations/IdentityServer/ConfigurationDb

溫故而知新:還記得在VS的Package Manager Console是如何執行命令創建遷移的嗎?

#第一步

Add-Migration InitialCreate

#第二步

Update-Database

6.初始化數據庫

現在我們已經完成了遷移,我們可以編寫代碼從遷移-migrations創建數據庫。我們還可以使用在前面的quickstart中定義的內存配置數據來爲數據庫初始化種子,當然這個seed最好只是在調試環境下執行。

官方提示:在這個快速入門中使用的方法主要是使IdentityServer更容易啓動和運行。您應該設計適合自己體系結構的數據庫創建和維護策略。

在Startup.cs中增加下面的初始化方法:

using System.Linq;
using IdentityServer4.EntityFramework.DbContexts;
using IdentityServer4.EntityFramework.Mappers;

private void InitializeDatabase(IApplicationBuilder app)
{
    using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope())
    {
        serviceScope.ServiceProvider.GetRequiredService<PersistedGrantDbContext>().Database.Migrate();

        var context = serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
        context.Database.Migrate();
        if (!context.Clients.Any())
        {
            foreach (var client in Config.Clients)
            {
                context.Clients.Add(client.ToEntity());
            }
            context.SaveChanges();
        }

        if (!context.IdentityResources.Any())
        {
            foreach (var resource in Config.IdentityResources)
            {
                context.IdentityResources.Add(resource.ToEntity());
            }
            context.SaveChanges();
        }

        if (!context.ApiResources.Any())
        {
            foreach (var resource in Config.Apis)
            {
                context.ApiResources.Add(resource.ToEntity());
            }
            context.SaveChanges();
        }
    }
}

public void Configure(IApplicationBuilder app)
{
    // this will do the initial DB population
    InitializeDatabase(app);

    // the rest of the code that was already here
    // ...
}

上面的InitializeDatabase方法可以方便地 seed the database,但是這種方法在每次運行應用程序時都留進去執行並不理想。一旦填充數據庫初始化數據之後,就可以考慮刪除對其之調用。

7.運行客戶端應用

這個就簡略些,上個命令即可

cd src\IdentityServer
dotnet run

長按二維碼關注

點外賣,先領券
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章