Add project files.

This commit is contained in:
Khwezi Mngoma
2026-06-05 22:07:25 +02:00
parent 59ea7de742
commit 437e8c5c08
978 changed files with 151911 additions and 0 deletions
@@ -0,0 +1,17 @@
// Copyright (c) Jan Škoruba. All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
namespace LiteCharmsSecurity.Admin.EntityFramework.Shared.Configuration.Schema
{
public class IdentityTableConfiguration
{
public string IdentityRoles { get; set; } = "Roles";
public string IdentityRoleClaims { get; set; } = "RoleClaims";
public string IdentityUserRoles { get; set; } = "UserRoles";
public string IdentityUsers { get; set; } = "Users";
public string IdentityUserLogins { get; set; } = "UserLogins";
public string IdentityUserClaims { get; set; } = "UserClaims";
public string IdentityUserTokens { get; set; } = "UserTokens";
public string IdentityUserPasskeys { get; set; } = "UserPasskeys";
}
}
@@ -0,0 +1,26 @@
// Copyright (c) Jan Škoruba. All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore;
using Skoruba.AuditLogging.EntityFramework.DbContexts;
using Skoruba.AuditLogging.EntityFramework.Entities;
namespace LiteCharmsSecurity.Admin.EntityFramework.Shared.DbContexts
{
public class AdminAuditLogDbContext : DbContext, IAuditLoggingDbContext<AuditLog>
{
public AdminAuditLogDbContext(DbContextOptions<AdminAuditLogDbContext> dbContextOptions)
: base(dbContextOptions)
{
}
public Task<int> SaveChangesAsync()
{
return base.SaveChangesAsync();
}
public DbSet<AuditLog> AuditLog { get; set; }
}
}
@@ -0,0 +1,54 @@
// Copyright (c) Jan Škoruba. All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
using System;
using Microsoft.EntityFrameworkCore;
using Skoruba.Duende.IdentityServer.Admin.EntityFramework.Admin.Storage.Interfaces;
using Skoruba.Duende.IdentityServer.Admin.EntityFramework.Admin.Storage.Entities;
using Skoruba.Duende.IdentityServer.Admin.EntityFramework.Admin.Storage.Helpers;
namespace LiteCharmsSecurity.Admin.EntityFramework.Shared.DbContexts;
public class AdminConfigurationDbContext : DbContext, IAdminConfigurationStoreDbContext
{
public DbSet<ConfigurationRule> ConfigurationRules { get; set; }
public AdminConfigurationDbContext(DbContextOptions<AdminConfigurationDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
ConfigureConfigurationRules(modelBuilder);
SeedDefaultRules(modelBuilder);
}
private void ConfigureConfigurationRules(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ConfigurationRule>(entity =>
{
entity.HasKey(e => e.Id);
entity.Property(e => e.RuleType).IsRequired();
entity.Property(e => e.ResourceType).IsRequired();
entity.Property(e => e.IssueType).IsRequired();
entity.Property(e => e.IsEnabled).IsRequired();
entity.Property(e => e.Configuration).HasMaxLength(2000);
entity.Property(e => e.MessageTemplate).HasMaxLength(500);
entity.Property(e => e.FixDescription).HasMaxLength(1000);
entity.Property(e => e.CreatedAt).IsRequired();
entity.HasIndex(e => e.RuleType).IsUnique();
});
}
private void SeedDefaultRules(ModelBuilder modelBuilder)
{
// Use ConfigurationRuleSeedHelper for consistent seed data across all providers
var configurationRules = Skoruba.Duende.IdentityServer.Admin.EntityFramework.Admin.Storage.Helpers.ConfigurationRuleSeedHelper.GetSeedData();
modelBuilder.Entity<ConfigurationRule>().HasData(configurationRules);
}
}
@@ -0,0 +1,41 @@
// Copyright (c) Jan Škoruba. All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using LiteCharmsSecurity.Admin.EntityFramework.Shared.Configuration.Schema;
using LiteCharmsSecurity.Admin.EntityFramework.Shared.Entities.Identity;
namespace LiteCharmsSecurity.Admin.EntityFramework.Shared.DbContexts
{
public class AdminIdentityDbContext : IdentityDbContext<UserIdentity, UserIdentityRole, string, UserIdentityUserClaim, UserIdentityUserRole, UserIdentityUserLogin, UserIdentityRoleClaim, UserIdentityUserToken, UserIdentityPasskey>
{
private readonly IdentityTableConfiguration _schemaConfiguration;
public AdminIdentityDbContext(DbContextOptions<AdminIdentityDbContext> options, IdentityTableConfiguration schemaConfiguration = null) : base(options)
{
_schemaConfiguration = schemaConfiguration ?? new IdentityTableConfiguration();
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
ConfigureIdentityContext(builder);
}
private void ConfigureIdentityContext(ModelBuilder builder)
{
builder.Entity<UserIdentityRole>().ToTable(_schemaConfiguration.IdentityRoles);
builder.Entity<UserIdentityRoleClaim>().ToTable(_schemaConfiguration.IdentityRoleClaims);
builder.Entity<UserIdentityUserRole>().ToTable(_schemaConfiguration.IdentityUserRoles);
builder.Entity<UserIdentity>().ToTable(_schemaConfiguration.IdentityUsers);
builder.Entity<UserIdentityUserLogin>().ToTable(_schemaConfiguration.IdentityUserLogins);
builder.Entity<UserIdentityUserClaim>().ToTable(_schemaConfiguration.IdentityUserClaims);
builder.Entity<UserIdentityUserToken>().ToTable(_schemaConfiguration.IdentityUserTokens);
builder.Entity<UserIdentityPasskey>().ToTable(_schemaConfiguration.IdentityUserPasskeys);
}
}
}
@@ -0,0 +1,37 @@
// Copyright (c) Jan Škoruba. All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
using Microsoft.EntityFrameworkCore;
using Skoruba.Duende.IdentityServer.Admin.EntityFramework.Constants;
using Skoruba.Duende.IdentityServer.Admin.EntityFramework.Entities;
using Skoruba.Duende.IdentityServer.Admin.EntityFramework.Interfaces;
namespace LiteCharmsSecurity.Admin.EntityFramework.Shared.DbContexts
{
public class AdminLogDbContext : DbContext, IAdminLogDbContext
{
public DbSet<Log> Logs { get; set; }
public AdminLogDbContext(DbContextOptions<AdminLogDbContext> options)
: base(options)
{
}
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
ConfigureLogContext(builder);
}
private void ConfigureLogContext(ModelBuilder builder)
{
builder.Entity<Log>(log =>
{
log.ToTable(TableConsts.Logging);
log.HasKey(x => x.Id);
log.Property(x => x.Level).HasMaxLength(128);
});
}
}
}
@@ -0,0 +1,50 @@
// Copyright (c) Jan Škoruba. All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
using Duende.IdentityServer.EntityFramework.DbContexts;
using Duende.IdentityServer.EntityFramework.Entities;
using Microsoft.EntityFrameworkCore;
using Skoruba.Duende.IdentityServer.Admin.EntityFramework.Interfaces;
namespace LiteCharmsSecurity.Admin.EntityFramework.Shared.DbContexts
{
public class IdentityServerConfigurationDbContext : ConfigurationDbContext<IdentityServerConfigurationDbContext>, IAdminConfigurationDbContext
{
public IdentityServerConfigurationDbContext(DbContextOptions<IdentityServerConfigurationDbContext> options)
: base(options)
{
}
public DbSet<ApiResourceProperty> ApiResourceProperties { get; set; }
public DbSet<IdentityResourceProperty> IdentityResourceProperties { get; set; }
public DbSet<ApiResourceSecret> ApiSecrets { get; set; }
public DbSet<ApiScopeClaim> ApiScopeClaims { get; set; }
public DbSet<IdentityResourceClaim> IdentityClaims { get; set; }
public DbSet<ApiResourceClaim> ApiResourceClaims { get; set; }
public DbSet<ClientGrantType> ClientGrantTypes { get; set; }
public DbSet<ClientScope> ClientScopes { get; set; }
public DbSet<ClientSecret> ClientSecrets { get; set; }
public DbSet<ClientPostLogoutRedirectUri> ClientPostLogoutRedirectUris { get; set; }
public DbSet<ClientIdPRestriction> ClientIdPRestrictions { get; set; }
public DbSet<ClientRedirectUri> ClientRedirectUris { get; set; }
public DbSet<ClientClaim> ClientClaims { get; set; }
public DbSet<ClientProperty> ClientProperties { get; set; }
public DbSet<ApiScopeProperty> ApiScopeProperties { get; set; }
public DbSet<ApiResourceScope> ApiResourceScopes { get; set; }
}
}
@@ -0,0 +1,16 @@
// Copyright (c) Jan Škoruba. All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
namespace LiteCharmsSecurity.Admin.EntityFramework.Shared.DbContexts
{
public class IdentityServerDataProtectionDbContext : DbContext, IDataProtectionKeyContext
{
public DbSet<DataProtectionKey> DataProtectionKeys { get; set; }
public IdentityServerDataProtectionDbContext(DbContextOptions<IdentityServerDataProtectionDbContext> options)
: base(options) { }
}
}
@@ -0,0 +1,17 @@
// Copyright (c) Jan Škoruba. All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
using Duende.IdentityServer.EntityFramework.DbContexts;
using Microsoft.EntityFrameworkCore;
using Skoruba.Duende.IdentityServer.Admin.EntityFramework.Interfaces;
namespace LiteCharmsSecurity.Admin.EntityFramework.Shared.DbContexts
{
public class IdentityServerPersistedGrantDbContext : PersistedGrantDbContext<IdentityServerPersistedGrantDbContext>, IAdminPersistedGrantDbContext
{
public IdentityServerPersistedGrantDbContext(DbContextOptions<IdentityServerPersistedGrantDbContext> options)
: base(options)
{
}
}
}
@@ -0,0 +1,12 @@
// Copyright (c) Jan Škoruba. All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
using Microsoft.AspNetCore.Identity;
namespace LiteCharmsSecurity.Admin.EntityFramework.Shared.Entities.Identity
{
public class UserIdentity : IdentityUser
{
}
}
@@ -0,0 +1,11 @@
// Copyright (c) Jan Škoruba. All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
using Microsoft.AspNetCore.Identity;
namespace LiteCharmsSecurity.Admin.EntityFramework.Shared.Entities.Identity
{
public class UserIdentityUserClaim : IdentityUserClaim<string>
{
}
}
@@ -0,0 +1,11 @@
// Copyright (c) Jan Škoruba. All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
using Microsoft.AspNetCore.Identity;
namespace LiteCharmsSecurity.Admin.EntityFramework.Shared.Entities.Identity
{
public class UserIdentityPasskey : IdentityUserPasskey<string>
{
}
}
@@ -0,0 +1,12 @@
// Copyright (c) Jan Škoruba. All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
using Microsoft.AspNetCore.Identity;
namespace LiteCharmsSecurity.Admin.EntityFramework.Shared.Entities.Identity
{
public class UserIdentityRole : IdentityRole
{
}
}
@@ -0,0 +1,12 @@
// Copyright (c) Jan Škoruba. All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
using Microsoft.AspNetCore.Identity;
namespace LiteCharmsSecurity.Admin.EntityFramework.Shared.Entities.Identity
{
public class UserIdentityRoleClaim : IdentityRoleClaim<string>
{
}
}
@@ -0,0 +1,12 @@
// Copyright (c) Jan Škoruba. All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
using Microsoft.AspNetCore.Identity;
namespace LiteCharmsSecurity.Admin.EntityFramework.Shared.Entities.Identity
{
public class UserIdentityUserLogin : IdentityUserLogin<string>
{
}
}
@@ -0,0 +1,12 @@
// Copyright (c) Jan Škoruba. All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
using Microsoft.AspNetCore.Identity;
namespace LiteCharmsSecurity.Admin.EntityFramework.Shared.Entities.Identity
{
public class UserIdentityUserRole : IdentityUserRole<string>
{
}
}
@@ -0,0 +1,12 @@
// Copyright (c) Jan Škoruba. All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
using Microsoft.AspNetCore.Identity;
namespace LiteCharmsSecurity.Admin.EntityFramework.Shared.Entities.Identity
{
public class UserIdentityUserToken : IdentityUserToken<string>
{
}
}
@@ -0,0 +1,25 @@
using System;
using Microsoft.Extensions.DependencyInjection;
using LiteCharmsSecurity.Admin.EntityFramework.Shared.Configuration.Schema;
namespace LiteCharmsSecurity.Admin.EntityFramework.Shared.Extensions
{
public static class ConfigurationSchemaServicesExtensions
{
public static IServiceCollection ConfigureAdminAspNetIdentitySchema(this IServiceCollection services,
Action<IdentityTableConfiguration> configureOptions)
{
if (configureOptions == null)
{
throw new ArgumentNullException(nameof(configureOptions));
}
var adminIdentitySchema = new IdentityTableConfiguration();
configureOptions(adminIdentitySchema);
services.AddSingleton(adminIdentitySchema);
return services;
}
}
}
@@ -0,0 +1,292 @@
// Copyright (c) Jan Škoruba. All Rights Reserved.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Linq;
using System.Threading.Tasks;
using Duende.IdentityServer.EntityFramework.Mappers;
using Duende.IdentityServer.Models;
using Duende.IdentityModel;
using Microsoft.AspNetCore.DataProtection.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Skoruba.AuditLogging.EntityFramework.DbContexts;
using Skoruba.AuditLogging.EntityFramework.Entities;
using Skoruba.Duende.IdentityServer.Admin.EntityFramework.Admin.Storage.Interfaces;
using Skoruba.Duende.IdentityServer.Admin.EntityFramework.Configuration.Configuration;
using Skoruba.Duende.IdentityServer.Admin.EntityFramework.Interfaces;
namespace LiteCharmsSecurity.Admin.EntityFramework.Shared.Helpers
{
public static class DbMigrationHelpers
{
/// <summary>
/// Generate migrations before running this method, you can use these steps bellow:
/// https://github.com/skoruba/Duende.IdentityServer.Admin#ef-core--data-access
/// </summary>
/// <param name="host"></param>
/// <param name="applyDbMigrationWithDataSeedFromProgramArguments"></param>
/// <param name="seedConfiguration"></param>
/// <param name="databaseMigrationsConfiguration"></param>
public static async Task<bool> ApplyDbMigrationsWithDataSeedAsync<TIdentityServerDbContext, TIdentityDbContext,
TPersistedGrantDbContext, TLogDbContext, TAuditLogDbContext, TDataProtectionDbContext, TAdminConfigurationDbContext, TUser, TRole>(
IHost host, bool applyDbMigrationWithDataSeedFromProgramArguments, SeedConfiguration seedConfiguration,
DatabaseMigrationsConfiguration databaseMigrationsConfiguration)
where TIdentityServerDbContext : DbContext, IAdminConfigurationDbContext
where TIdentityDbContext : DbContext
where TPersistedGrantDbContext : DbContext, IAdminPersistedGrantDbContext
where TLogDbContext : DbContext, IAdminLogDbContext
where TAuditLogDbContext : DbContext, IAuditLoggingDbContext<AuditLog>
where TDataProtectionDbContext : DbContext, IDataProtectionKeyContext
where TAdminConfigurationDbContext : DbContext, IAdminConfigurationStoreDbContext
where TUser : IdentityUser, new()
where TRole : IdentityRole, new()
{
var migrationComplete = false;
using (var serviceScope = host.Services.CreateScope())
{
var services = serviceScope.ServiceProvider;
if ((databaseMigrationsConfiguration != null && databaseMigrationsConfiguration.ApplyDatabaseMigrations)
|| (applyDbMigrationWithDataSeedFromProgramArguments))
{
migrationComplete = await EnsureDatabasesMigratedAsync<TIdentityDbContext, TIdentityServerDbContext, TPersistedGrantDbContext, TLogDbContext, TAuditLogDbContext, TDataProtectionDbContext, TAdminConfigurationDbContext>(services);
}
if ((seedConfiguration != null && seedConfiguration.ApplySeed)
|| (applyDbMigrationWithDataSeedFromProgramArguments))
{
var seedComplete = await EnsureSeedDataAsync<TIdentityServerDbContext, TUser, TRole>(services);
return migrationComplete && seedComplete;
}
}
return migrationComplete;
}
public static async Task<bool> EnsureDatabasesMigratedAsync<TIdentityDbContext, TConfigurationDbContext, TPersistedGrantDbContext, TLogDbContext, TAuditLogDbContext, TDataProtectionDbContext, TAdminConfigurationDbContext>(IServiceProvider services)
where TIdentityDbContext : DbContext
where TPersistedGrantDbContext : DbContext
where TConfigurationDbContext : DbContext
where TLogDbContext : DbContext
where TAuditLogDbContext : DbContext
where TDataProtectionDbContext : DbContext
where TAdminConfigurationDbContext : DbContext, IAdminConfigurationStoreDbContext
{
var pendingMigrationCount = 0;
using (var scope = services.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
using (var context = scope.ServiceProvider.GetRequiredService<TPersistedGrantDbContext>())
{
await context.Database.MigrateAsync();
pendingMigrationCount += (await context.Database.GetPendingMigrationsAsync()).Count();
}
using (var context = scope.ServiceProvider.GetRequiredService<TIdentityDbContext>())
{
await context.Database.MigrateAsync();
pendingMigrationCount += (await context.Database.GetPendingMigrationsAsync()).Count();
}
using (var context = scope.ServiceProvider.GetRequiredService<TConfigurationDbContext>())
{
await context.Database.MigrateAsync();
pendingMigrationCount += (await context.Database.GetPendingMigrationsAsync()).Count();
}
using (var context = scope.ServiceProvider.GetRequiredService<TLogDbContext>())
{
await context.Database.MigrateAsync();
pendingMigrationCount += (await context.Database.GetPendingMigrationsAsync()).Count();
}
using (var context = scope.ServiceProvider.GetRequiredService<TAuditLogDbContext>())
{
await context.Database.MigrateAsync();
pendingMigrationCount += (await context.Database.GetPendingMigrationsAsync()).Count();
}
using (var context = scope.ServiceProvider.GetRequiredService<TDataProtectionDbContext>())
{
await context.Database.MigrateAsync();
pendingMigrationCount += (await context.Database.GetPendingMigrationsAsync()).Count();
}
using (var context = scope.ServiceProvider.GetRequiredService<TAdminConfigurationDbContext>())
{
await context.Database.MigrateAsync();
pendingMigrationCount += (await context.Database.GetPendingMigrationsAsync()).Count();
}
}
return pendingMigrationCount == 0;
}
public static async Task<bool> EnsureSeedDataAsync<TIdentityServerDbContext, TUser, TRole>(IServiceProvider serviceProvider)
where TIdentityServerDbContext : DbContext, IAdminConfigurationDbContext
where TUser : IdentityUser, new()
where TRole : IdentityRole, new()
{
using (var scope = serviceProvider.GetRequiredService<IServiceScopeFactory>().CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<TIdentityServerDbContext>();
var userManager = scope.ServiceProvider.GetRequiredService<UserManager<TUser>>();
var roleManager = scope.ServiceProvider.GetRequiredService<RoleManager<TRole>>();
var idsDataConfiguration = scope.ServiceProvider.GetRequiredService<IdentityServerData>();
var idDataConfiguration = scope.ServiceProvider.GetRequiredService<IdentityData>();
await EnsureSeedIdentityServerData(context, idsDataConfiguration);
await EnsureSeedIdentityData(userManager, roleManager, idDataConfiguration);
}
return true;
}
/// <summary>
/// Generate default admin user / role
/// </summary>
private static async Task EnsureSeedIdentityData<TUser, TRole>(UserManager<TUser> userManager,
RoleManager<TRole> roleManager, IdentityData identityDataConfiguration)
where TUser : IdentityUser, new()
where TRole : IdentityRole, new()
{
// adding roles from seed
foreach (var r in identityDataConfiguration.Roles)
{
if (!await roleManager.RoleExistsAsync(r.Name))
{
var role = new TRole
{
Name = r.Name
};
var result = await roleManager.CreateAsync(role);
if (result.Succeeded)
{
foreach (var claim in r.Claims)
{
await roleManager.AddClaimAsync(role, new System.Security.Claims.Claim(claim.Type, claim.Value));
}
}
}
}
// adding users from seed
foreach (var user in identityDataConfiguration.Users)
{
var identityUser = new TUser
{
UserName = user.Username,
Email = user.Email,
EmailConfirmed = true
};
var userByUserName = await userManager.FindByNameAsync(user.Username);
var userByEmail = await userManager.FindByEmailAsync(user.Email);
// User is already exists in database
if (userByUserName != default || userByEmail != default)
{
continue;
}
// if there is no password we create user without password
// user can reset password later, because accounts have EmailConfirmed set to true
var result = !string.IsNullOrEmpty(user.Password)
? await userManager.CreateAsync(identityUser, user.Password)
: await userManager.CreateAsync(identityUser);
if (result.Succeeded)
{
foreach (var claim in user.Claims)
{
await userManager.AddClaimAsync(identityUser, new System.Security.Claims.Claim(claim.Type, claim.Value));
}
foreach (var role in user.Roles)
{
await userManager.AddToRoleAsync(identityUser, role);
}
}
}
}
/// <summary>
/// Generate default clients, identity and api resources
/// </summary>
private static async Task EnsureSeedIdentityServerData<TIdentityServerDbContext>(TIdentityServerDbContext context, IdentityServerData identityServerDataConfiguration)
where TIdentityServerDbContext : DbContext, IAdminConfigurationDbContext
{
foreach (var resource in identityServerDataConfiguration.IdentityResources)
{
var exits = await context.IdentityResources.AnyAsync(a => a.Name == resource.Name);
if (exits)
{
continue;
}
await context.IdentityResources.AddAsync(resource.ToEntity());
}
foreach (var apiScope in identityServerDataConfiguration.ApiScopes)
{
var exits = await context.ApiScopes.AnyAsync(a => a.Name == apiScope.Name);
if (exits)
{
continue;
}
await context.ApiScopes.AddAsync(apiScope.ToEntity());
}
foreach (var resource in identityServerDataConfiguration.ApiResources)
{
var exits = await context.ApiResources.AnyAsync(a => a.Name == resource.Name);
if (exits)
{
continue;
}
foreach (var s in resource.ApiSecrets)
{
s.Value = s.Value.ToSha256();
}
await context.ApiResources.AddAsync(resource.ToEntity());
}
foreach (var client in identityServerDataConfiguration.Clients)
{
var exits = await context.Clients.AnyAsync(a => a.ClientId == client.ClientId);
if (exits)
{
continue;
}
foreach (var secret in client.ClientSecrets)
{
secret.Value = secret.Value.ToSha256();
}
client.Claims = client.ClientClaims
.Select(c => new ClientClaim(c.Type, c.Value))
.ToList();
await context.Clients.AddAsync(client.ToEntity());
}
await context.SaveChangesAsync();
}
}
}
@@ -0,0 +1,28 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net10.0</TargetFramework>
<Description>DbContexts and Identity entities for the administration of the Duende IdentityServer and Asp.Net Core Identity</Description>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.DataProtection.EntityFrameworkCore" Version="10.0.7" />
<PackageReference Include="Skoruba.AuditLogging.EntityFramework" Version="3.0.0" />
<PackageReference Include="Skoruba.Duende.IdentityServer.Admin.EntityFramework.Admin.Storage" Version="3.0.0-rc4" />
<PackageReference Include="Skoruba.Duende.IdentityServer.Admin.EntityFramework.Configuration" Version="3.0.0-rc4" />
</ItemGroup>
</Project>