使用MySql对IdentityServer4进行持久化
哈喽大家好,看见网上很少有使用MySql进行持久化的,毕竟又很多坑,说句实话,就连 MySql.Data.EntityFrameworkCore 都有问题,不知道是.net core更新太快还是其它的问题,但毕竟mssql驱动是没问题的,感觉还是私心太大了。不得以之下选择了一个第三方的驱动 Pomelo.EntityFrameworkCore.MySql 驱动,在这里主要是你安装了它,你就又了它的设计器,但你还需要你安装EFCore的设计器,因为你执行dotnet命令迁移的时候还得靠它,好吧,我们继续,在你的应用程序中最好保持这几个包。能多不能少。
<ItemGroup> <PackageReference Include="IdentityServer4" Version="2.0.0-rc1" /> <PackageReference Include="IdentityServer4.AspNetIdentity" Version="2.0.0-rc1" /> <PackageReference Include="IdentityServer4.EntityFramework" Version="2.0.0-rc1" /> <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" /> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.0.0" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.0.0" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.0.0" /> <PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="2.0.0-rtm-10062" /> <PackageReference Include="Pomelo.EntityFrameworkCore.MySql.Design" Version="1.1.2" /> </ItemGroup>
就这样,在Model里创建两个类,一个是用户、一个是关系,这个是Identity的类。其实这个和IdentityServer是没有多大关系的。主要是为了扩展一些东西,比如你需要其它的字段?
public class ApplicationRole : IdentityRole{} public class ApplicationUser : IdentityUser{}
随后我们定义IdentityDbContext,将我们自己定义的两个类放进去,它是个泛型的。
public class ApplicationDbContext : IdentityDbContext<ApplicationUser, ApplicationRole, string> { public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options) { } protected override void OnModelCreating(ModelBuilder builder) { base.OnModelCreating(builder); // Customize the ASP.NET Identity model and override the defaults if needed. // For example, you can rename the ASP.NET Identity table names and more. // Add your customizations after calling base.OnModelCreating(builder); } }
再之后我们就可以注入到.Net Core的服务里了,IdentityServer的数据库中有三个大类,有AspNet的票据用户、资源的管理、以及一些操作的记录。这里你可以用一个database,你也可以分开。
public void ConfigureServices(IServiceCollection services) { // Add framework services. services.AddDbContext<ApplicationDbContext>(options => options.UseMySql(Configuration.GetConnectionString("DefaultConnection"))); services.AddIdentity<ApplicationUser, ApplicationRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders(); services.AddMvc(); string migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name; services.AddIdentityServer() .AddConfigurationStore(options => { options.ConfigureDbContext = builder => builder.UseMySql(Configuration.GetConnectionString("DefaultConnection"), sql => sql.MigrationsAssembly(migrationsAssembly)); }) .AddOperationalStore(options => { options.ConfigureDbContext = builder => builder.UseMySql(Configuration.GetConnectionString("DefaultConnection"), sql => sql.MigrationsAssembly(migrationsAssembly)); // this enables automatic token cleanup. this is optional. options.EnableTokenCleanup = true; options.TokenCleanupInterval = 30; }); }
随后注册IdentityServer服务,这个里面调用了 InitializeDatabase 方法为了初始化的迁移数据。
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { InitializeDatabase(app); if (env.IsDevelopment()) app.UseDeveloperExceptionPage(); else app.UseExceptionHandler("/Home/Error"); app.UseIdentityServer(); }
这个方法就很有意思了,获取了.net core的服务实例,然后对我的Context进行了更新迁移,直接将Config中的内存数据添加到了数据库中。
private void InitializeDatabase(IApplicationBuilder app) { using (var serviceScope = app.ApplicationServices.GetService<IServiceScopeFactory>().CreateScope()) { serviceScope.ServiceProvider.GetRequiredService<ApplicationDbContext>().Database.Migrate(); serviceScope.ServiceProvider.GetRequiredService<PersistedGrantDbContext>().Database.Migrate(); var context = serviceScope.ServiceProvider.GetRequiredService<ConfigurationDbContext>(); context.Database.Migrate(); if (!context.Clients.Any()) { foreach (var client in Config.GetClients()) { context.Clients.Add(client.ToEntity()); } context.SaveChanges(); } if (!context.IdentityResources.Any()) { foreach (var resource in Config.GetIdentityResources()) { context.IdentityResources.Add(resource.ToEntity()); } context.SaveChanges(); } if (!context.ApiResources.Any()) { foreach (var resource in Config.GetApiResources()) { context.ApiResources.Add(resource.ToEntity()); } context.SaveChanges(); } }
最后你需要执行三个命令,执行EFCore的数据迁移。
dotnet ef migrations add InitialIdentityServerPersistedGrantDbMigration -c PersistedGrantDbContext -o Data/Migrations/IdentityServer/PersistedGrantDb dotnet ef migrations add InitialIdentityServerConfigurationDbMigration -c ConfigurationDbContext -o Data/Migrations/IdentityServer/ConfigurationDb dotnet ef migrations add InitialIdentityServerApplicationDbMigration -c ApplicationDbContext -o Data/Migrations/IdentityServer/ApplicationDb
就这样,生成完毕我们测试一下程序。
Ok,一些正常。