Identityserver4 series supports data persistence

Time:2021-10-11

1、 Foreword

In the introduction of the previous chapter, some basic configurations, such as API resources, client resources and other data, as well as operation data such as tokens issued during use, are realized by storing operation data and configuration data in memory. In actual development and production, how do we deal with data persistence?

At this timeIdentityServer4It has good scalability, one of which is forIdentityServerThe storage mechanism of the required data for persistence operation.

How to configureIdentityServerTo useEntityFramework(EF) as the storage mechanism of this data, store these data inSql ServerDatabase, which is more in line with the needs of our actual production environment.

2、 First acquaintance

In ourIdentityServer4The two officially defined contexts in are that there are two types of data that need to be persisted to the database:

1、Configuration data(resource, client, identity)// Here is the corresponding configuration contextConfigurationDbContext

2、IdentityServerGenerated during useOperation data(tokens, codes and user authorization information concents)// Here is the corresponding operation contextPersistedGrantDbContext

These two contexts and corresponding data models have been officially encapsulated by identity server 4, we do not need to do any additional operations. We can use it directly by migrating.

2.1 ConfigurationDb

ConfigurationDbContext(identityserver configuration data) – responsible for the configuration storage of client, resource and CORS settings in the database;

If you need to load client, identity resources, API resources, or CORS data from EF supported databases (instead of using in memory configuration), you can use configuration storage. This support providesIClientStoreIResura StoreandICorsPolicyServiceImplementation of extensibility point. These implementations use the nameConfigurationDbContextofdbcontextDerived classes model tables in a database.

2.2 PersistedGrantDb

PersistedGrantDbContext(identityserver operational data.) – responsible for storing consent, authorization code, refresh token and reference token;

If you need to load authorization grants, consents, and tokens (refresh and reference) from a database supported by EF (instead of the default in memory database), you can use the action store. This support providesIPersistedGrantStoreImplementation of extension point. The implementation uses the namePersistedGrantDbContextofdbcontextDerived classes model tables in a database.

3、 Practice

3.1 new site

Establish an ASP. Net core project of MVC and use MVC template

3.2 nuget package

IdentityServer4.EntityFrameworkAnd EF related packages

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

Because what is used in this article isSqlServerDatabase, so you need to install the corresponding EF package to support the database.

Microsoft.EntityFrameworkCore.SqlServer

3.3 database context

appsettings.json

"ConnectionStrings": {
    "DataContext": "data source=.;initial catalog=Yuan.Idp;user id=sa;password=123456;",   
  }

Configure connection database

var connectionString = Configuration.GetConnectionString("DataContext");
 if (connectionString == "")
 {
      Throw new exception ("database configuration exception");
 }

2. Configure database service

Add the following code to the configureservices method in startup.cs:

public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews();
            var connectionString = Configuration.GetConnectionString("DataContext");
            if (connectionString == "")
            {
                Throw new exception ("database configuration 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 = > // add configuration data (configurationdbcontext context user configuration data)
            {
                options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
            }). Addoperationalstore (options = > // add operation data (persistedgrantdbcontext context temporary data (such as authorization and refresh tokens))
            {
                options.ConfigureDbContext = builder => builder.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
                //Automatically clean up tokens, optional
                options.EnableTokenCleanup = true;
                //Automatically clean up tokens, optional
                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 migrating data

3.4.1 console migration

Method 1:

EF tools need to be added to installMicrosoft.EntityFrameworkCore.Tools, migrate

1、add-migration InitialIdentityServerPersistedGrantDbMigration -c PersistedGrantDbContext -o Data/Migrations/PersistedGrantDb 
   2、add-migration InitialIdentityServerConfigurationDbMigration -c ConfigurationDbContext -o Data/Migrations/ConfigurationDb 
   3、update-database -Context PersistedGrantDbContext
   4、update-database -Context ConfigurationDbContext

3.4.2 in the command window

Method 2:

To determine whether command line migration is supported, you can open a command power shell in the directory where the project is located and run the command dotnet EF. It should be as follows:

Dotnet EF cannot execute because the specified command or file cannot be found

Since 3.0, the EF core command line tool (dotnet EF) is not in the. Net core SDK and needs to be installed separately. The command is as follows:

dotnet tool install --global dotnet-ef

To create a migration, open a command prompt in the identity server project directory. Run both commands at the command prompt:

1. dotnet ef migrations add InitialIdentityServerPersistedGrantDbMigration -c PersistedGrantDbContext -o Data/Migrations/PersistedGrantDb
2. dotnet ef migrations add InitialIdentityServerConfigurationDbMigration -c ConfigurationDbContext -o Data/Migrations/ConfigurationDb
 
#Generate
1. update-database -c PersistedGrantDbContext   
2. update-database -c ConfigurationDbContext

3.5 display database

(picture from network)

3.6 initializing the database

In the previous chapter, we defined the operation implemented by the memory configuration data. In this chapter, we perform data persistence operation, which can migrate the previous memory data as seed processing to the created database for initialization.

Reference article:User data migration

3.6.1 creating files

Create the seeddata.cs file to initialize the basic data:

public class SeedData
    {
        public static void EnsureSeedData(IServiceProvider serviceProvider)
        {
            Console.WriteLine("Seeding database...");

            using (var scope = serviceProvider.GetRequiredService().CreateScope())
            {
                scope.ServiceProvider.GetService().Database.Migrate();

               var context = scope.ServiceProvider.GetRequiredService();
                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 initializing");
                foreach (var client in Config.GetClients)
                {
                    context.Clients.Add(client.ToEntity());
                }
                context.SaveChanges();
            }

            if (!context.IdentityResources.Any())
            {
                Console.writeline ("identityresources initializing");
                foreach (var resource in Config.GetIdentityResources)
                {
                    context.IdentityResources.Add(resource.ToEntity());
                }
                context.SaveChanges();
            }

            if (!context.ApiResources.Any())
            {
                Console.writeline ("apiresources initializing");
                foreach (var resource in Config.GetApiResources)
                {
                    context.ApiResources.Add(resource.ToEntity());
                }
                context.SaveChanges();
            }

            if (!context.ApiScopes.Any())
            {
                Console.writeline ("APIs scopes initializing");
                foreach (var resource in Config.GetApiScopes)
                {
                    context.ApiScopes.Add(resource.ToEntity());
                }
                context.SaveChanges();
            }
        }
    }

Configure content to view previous chapter content filesConfig.csperhapsProject address.

3.6.2 calling method

Then we can go from the main entranceMainMethod calls it:

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 program operation

inputdotnet run /seed 

3.6.4 effect

4、 Question

4.1 prompt context not found

For the two contexts mentioned above, if we directly execute the migration command, an error will be reported. For example, we directly migrate the persistedgrantdbcontext context:

Because the migration targets do not match, the migration assembly needs to be changed, such as

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

Therefore, you need to configure the corresponding service in the project. In the startup.cs startup file, configure the service configureservice and configure the EF operation database

Solution: refer to the in the practice section aboveDatabase context.

  1. Get database connection string

  2. Configure database services

4.2 dotnet EF cannot be executed

The specified command or file could not be found

Since 3.0, the EF core command line tool (dotnet EF) is not in the. Net core SDK and needs to be installed separately. The command is as follows:

dotnet tool install –global dotnet-ef

5、 Summary

  1. Briefly introducedIdentityServer4Persistent storage mechanism related configuration and operation data, data migration, and application practice.
  2. This chapter does not describe the storage of persistent operations for users becauseIdentityServer4This supports access to other authentication methods, so you can make reasonable adjustments according to your needsextendFor example, we can useIdentity of ASP. Net coreIdentity authentication mechanismImplementation extensionOf course, you can also define corresponding operations by yourself, which will be described in subsequent chapters.
  3. If there is something wrong or incomprehensible, I hope you can make more corrections, ask questions, discuss together, keep learning and make common progress.
  4. Project address

6、 Attach

EF supports persistent configuration and operation data

Recommended Today

SQL statement of three-level linkage of provinces, cities and counties

The first is the table creation statement Copy codeThe code is as follows: CREATE TABLE `t_address_province` ( `id` INT AUTO_ Increment primary key comment ‘primary key’,`Code ` char (6) not null comment ‘province code’,`Name ` varchar (40) not null comment ‘province name’)Engine = InnoDB default charset = utf8 comment = ‘province information table’; CREATE TABLE […]