(十一)React Ant Design Pro + .Net5 WebApi:后端環境搭建-IdentityServer4(三)持久化


一、前言

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

五、代碼已上傳

https://github.com/WinterSir/IdentityServer4.GrantTypesDemo


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM