使用 EntityFramework Core 进行配置和操作数据

注意

除了手动配置EF支持外,还有一个 IdentityServer 模板可用于创建具有EF支持的新项目。使用创建它。有关更多信息,请参见此处dotnet new is4ef

IdentityServer4.EntityFramework 

我们正在向数据库迁移两种类型的数据库。第一个是配置数据(资源和客户端)。第二个是 IdentityServer 在使用时产生的操作数据(令牌,代码和接口)。这些存储使用接口建模,我们在 IdentityServer4.EntityFramework Nuget 包中提供这些接口的 EF 实现

通过添加 IdentityServer 项目的 IdentityServer4.EntityFramework Nuget 包的引用开始

../_images/8_nuget.png

使用 SqlServer 

鉴于 EF 的灵活性,您可以使用任何 EF 支持的数据库。对于本快速入门,我们将使用 Visual Studio 附带的SqlServer 的 LocalDb 版本。

数据库架构更改和使用 EF 迁移

该 IdentityServer4.EntityFramework 包中包含从 IdentityServer 的模型映射实体类。作为 IdentityServer 的车型变化,所以会在实体类 IdentityServer4.EntityFramework当您使用 IdentityServer4.EntityFramework 并随着时间的推移升级时,您将负责自己的数据库架构以及实体类更改时该架构所需的更改。管理这些更改的一种方法是使用 EF 迁移,此快速入门将显示如何完成此操作。如果迁移不是您的首选,那么您可以以任何您认为合适的方式管理架构更改。

注意

IdentityServer4.EntityFramework中的实体维护SqlServer的SQL脚本。点击这里

用于迁移的 EF 工具

除了使用 EF 迁移跟踪架构更改之外,我们还将使用它在数据库中创建初始架构。这需要使用 EF Core 工具(此处有更多详细信息)。我们现在将添加它们,不幸的是,这必须通过手动编辑 .csproj 文件来完成通过右键单击项目来编辑 .csproj,然后选择“编辑 projectname.csproj”:

注意

根据您为 IdentityServer 主机创建初始项目的方式,您可能已在 csproj 文件中配置了这些工具如果是,您可以跳到下一部分。

../_images/8_edit_csproj.png

然后在结尾</ Project>元素之前添加以下代码段

<ItemGroup>
  <DotNetCliToolReference Include="Microsoft.EntityFrameworkCore.Tools.DotNet" Version="2.0.0" />
</ItemGroup>

它应该看起来像这样:

../_images/8_csproj.png

保存并关闭文件。要测试您是否正确安装了这些工具,可以在与项目相同的目录中打开命令 shell 并运行 dotnet ef它应该如下所示:

../_images/8_dotnet_ef_command_line.png

配置存储

接下来的步骤是,以取代当前呼叫AddInMemoryClientsAddInMemoryIdentityResourcesAddInMemoryApiResourcesConfigureServices在方法Startup.cs我们将使用以下代码替换它们:

const string connectionString = @"Data Source=(LocalDb)\MSSQLLocalDB;database=IdentityServer4.Quickstart.EntityFramework-2.0.0;trusted_connection=yes;";
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;

// configure identity server with in-memory stores, keys, clients and scopes
services.AddIdentityServer()
    .AddDeveloperSigningCredential()
    .AddTestUsers(Config.GetUsers())
    // this adds the config data from DB (clients, resources)
    .AddConfigurationStore(options =>
    {
        options.ConfigureDbContext = builder =>
            builder.UseSqlServer(connectionString,
                sql => sql.MigrationsAssembly(migrationsAssembly));
    })
    // this adds the operational data from DB (codes, tokens, consents)
    .AddOperationalStore(options =>
    {
        options.ConfigureDbContext = builder =>
            builder.UseSqlServer(connectionString,
                sql => sql.MigrationsAssembly(migrationsAssembly));

        // this enables automatic token cleanup. this is optional.
        options.EnableTokenCleanup = true;
        options.TokenCleanupInterval = 30;
    });

您可能需要将这些命名空间添加到文件中:

using Microsoft.EntityFrameworkCore;
using System.Reflection;

上面的代码是对连接字符串进行硬编码,如果您愿意,可以随意更改。此外,调用AddConfigurationStoreAddOperationalStore注册 EF 支持的存储实现。

传递给这些 API 的“构建器”回调函数是 EF 机制,允许您为这两个存储中的每一个配置DbContextOptionsBuilderfor DbContext这就是我们的DbContext类可以使用您要使用的数据库提供程序进行配置的方式。在这种情况下,通过调用UseSqlServer我们正在使用 SqlServer。您也可以看出,这是提供连接字符串的位置。

“options”回调函数用于UseSqlServer配置定义 EF 迁移的程序集。EF 需要使用迁移来定义数据库的模式。

注意

托管应用程序负责定义这些迁移,因为它们特定于您的数据库和提供程序。

我们接下来会添加迁移。

添加迁移

要创建迁移,请在 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

它应该看起来像这样:

../_images/8_add_migrations.png

您现在应该在项目中看到〜/ Data / Migrations / IdentityServer文件夹。其中包含新创建的迁移的代码。

注意

如果您的数据库项目是一个单独的类库,并修复了错误“无法创建类型的对象”<您的名字> DbContext'。将“IDesignTimeDbContextFactory”的实现添加到项目中,或者参阅https://go.microsoft.com/fwlink/?linkid=851728以获取在设计时支持的其他模式。通过添加IDesignTimeDbContextFactory的实现,您还需要PersistedGrantDbContext和ConfigurationDbContext的工厂实现。

初始化数据库

现在我们已经进行了迁移,我们可以编写代码来从迁移中创建数据库。我们还将使用我们在之前的快速入门中定义的内存配置数据来为数据库设定种子。

在 Startup.cs 中添加此方法以帮助初始化数据库:

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

然后我们可以从Configure方法中调用它

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    // this will do the initial DB population
    InitializeDatabase(app);

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

现在,如果运行 IdentityServer 项目,则应创建数据库并使用快速入门配置数据进行种子设定。您应该能够使用SQL Server Management Studio 或 Visual Studio 来连接和检查数据。

../_images/8_database.png

注意

上面的InitializeDatabase辅助API可以方便地为数据库设定种子,但是这种方法并不适合每次运行应用程序时执行。填充数据库后,请考虑删除对API的调用。

运行客户端应用程序

您现在应该能够运行任何现有的客户端应用程序并登录,获取令牌并调用 API - 所有这些都基于数据库配置。

注意

本节中的代码仍然依赖于 Config.cs 及其虚构用户 Alice 和 Bob 。如果您的用户列表很简短且静态,则调整后的 Config.cs 版本可能就足够了,但您可能希望在数据库中动态管理更大且更流畅的用户列表。ASP.NET Identity 是一个需要考虑的选项,下一节的快速入门列出了此解决方案的示例实现。

nidie.com.cn - 用心与你沟通