IdentityServer4 SetUp with SQL Server
Introduction:
In this blog you will learn how to store the operational and configuration data in MS SQL Database with ASP.NET and Entityframework Core.
Prerequisites:
- Basic knowledge in building ASP.NET Core application.
- If you are new to IdentityServer4 with ASP.NET Core 6, I strongly recommend you to read some of IdentityServer4 from https://identityserver4.readthedocs.io/en/latest/quickstarts/5_entityframework.html.
Table of Content
- Create a new ASP.NET Core Project
- Add Entity framework libraries
- Configure Operational and Configuration Store
- Establish the database connection
- Add migration and update the database
- Test the Service
Create a New ASP.NET Core Project
Create an empty ASP.NET Core project with .NET 6 framework using Visual Studio.
This project will act as an actual IdentityServer4. I have added this project into solution and named it as Ids4_EFCore.
My solution
Add Entity Framework Libraries
Add following libraries into a project using NuGet Package manager
- IdentityServer4.EntityFramework
- Microsoft.EntityFrameworkCore.SqlServer
- Microsoft.EntityFrameworkCore.Tools
- System.Configuration.ConfigurationManager
IdentityServer4.EntityFramework -This package is used to incorporate EntityFramework to IdentityServer4, it acts as an EntityFramework persistence layer for IdentityServer4.
Microsoft.EntityFrameworkCore.SqlServer– To include the Microsoft SQL Server database provider for EntityFramework.
Microsoft.EntityFrameworkCore.Tools– Entity Framework Core Tools for the NuGet Package Manager Console in Visual Studio. By including this package, we can use the EF Core migration commands in NuGet Package manager console.
Configure Operational and Configurational Store
Open Program.cs file from the project and add following code
string connectionString = builder.Configuration.GetConnectionString("localdb");
var migrationsAssembly = typeof(Program).Assembly.GetName().Name;
builder.Services.AddIdentityServer()
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
})
.AddOperationalStore(options =>
{
options.ConfigureDbContext = b => b.UseSqlServer(connectionString, sql => sql.MigrationsAssembly(migrationsAssembly));
options.EnableTokenCleanup = true;
});
The above code will configure and add the identity Server and it tells to Use SQL Server to store the configurational and operational data.
Add Config file in the project, and add a below code
public static class Config
{
public static IEnumerable<IdentityResource> Ids =>
new List<IdentityResource>
{
new IdentityResources.OpenId(),
new IdentityResources.Profile(),
};
public static IEnumerable<ApiResource> Apis =>
new List<ApiResource>
{
new ApiResource("api1", "My API")
};
public static IEnumerable<Client> Clients =>
new List<Client>
{
// machine to machine client
new Client
{
ClientId = "client",
ClientSecrets = { new Secret("secret".Sha256()) },
AllowedGrantTypes = GrantTypes.ClientCredentials,
// scopes that client has access to
AllowedScopes = { "api1" }
},
// interactive ASP.NET Core MVC client
new Client
{
ClientId = "mvc",
ClientSecrets = { new Secret("secret".Sha256()) },
AllowedGrantTypes = GrantTypes.Code,
RequireConsent = false,
RequirePkce = true,
// where to redirect to after login
RedirectUris = { "http://localhost:5002/signin-oidc" },
// where to redirect to after logout
PostLogoutRedirectUris = { "http://localhost:5002/signout-callback-oidc" },
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"api1"
},
AllowOfflineAccess = true
},
// JavaScript Client
new Client
{
ClientId = "js",
ClientName = "JavaScript Client",
AllowedGrantTypes = GrantTypes.Code,
RequirePkce = true,
RequireClientSecret = false,
RedirectUris = { "http://localhost:5003/callback.html" },
PostLogoutRedirectUris = { "http://localhost:5003/index.html" },
AllowedCorsOrigins = { "http://localhost:5003" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"api1"
}
}
};
}
The above code will seed a configurational data into database. In production environment it should be dynamic.
Let’s config database seeding in Program.cs file
if(app.Environment.IsDevelopment())
{
InitializeDatabase(app);
}
static 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.Ids)
{
context.IdentityResources.Add(resource.ToEntity());
}
context.SaveChanges();
}
if (!context.ApiResources.Any())
{
foreach (var resource in Config.Apis)
{
context.ApiResources.Add(resource.ToEntity());
}
context.SaveChanges();
}
}
The above code will seed the static data from config file into database, when you start the application.
Establish the database connection
Establish the database connection by providing the connection string in appsettings.json
"ConnectionStrings": {
"localdb": "Server=[your server name];Database=[your database name];Integrated Security= SSPI"
},
Add migration and update the database
Use Add-Migration command in NuGet Package Manager console.
Use below command for ConfigurationDbContext Migration
“Add-Migration InitialConfigurationDbMigration -context ConfigurationDbContext”
Use below command for PersistedGrantDbContext Migration
“Add-Migration InitialPersistedGrantDbMigration -context PersistedGrantDbContext”
It will add the migration information as shown in below figure.
Use update-database command from Package Manager Console in Visual Studio to create/update the database tables based on the migration information. Make sure you have given a database connection string.
List of tables created
Run the application, the client information in the config file will be inserted into respective tables.
Client information in table
There client information’s are inserted into a table based on the static data(Test Users) added/defined in config.cs file.
Test the Service
Let’s test the service using POSTMAN
we got a token by passing the valid client credentials
Comments
Post a Comment