Compare commits
8 Commits
66ed34b664
...
06260e0edb
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
06260e0edb | ||
|
|
2d675a16ad | ||
|
|
5469b20e4f | ||
|
|
6f5b4efefb | ||
|
|
b6b12c7702 | ||
|
|
ce716d2bab | ||
|
|
bf672d8b8c | ||
|
|
ed29c9f990 |
@@ -1,4 +1,5 @@
|
|||||||
using DigitalData.Core.Security.Cryptographer;
|
using DigitalData.Core.Abstractions.Security;
|
||||||
|
using DigitalData.Core.Security.Cryptographer;
|
||||||
|
|
||||||
namespace DigitalData.Core.Security.Config
|
namespace DigitalData.Core.Security.Config
|
||||||
{
|
{
|
||||||
@@ -55,9 +56,14 @@ namespace DigitalData.Core.Security.Config
|
|||||||
|
|
||||||
public IEnumerable<RSADecryptor> Decryptors { get; init; } = new List<RSADecryptor>();
|
public IEnumerable<RSADecryptor> Decryptors { get; init; } = new List<RSADecryptor>();
|
||||||
|
|
||||||
|
public IEnumerable<TokenDescription> TokenDescriptions { get; init; } = new List<TokenDescription>();
|
||||||
|
|
||||||
public RSADecryptor? Vault { get; init; }
|
public RSADecryptor? Vault { get; init; }
|
||||||
|
|
||||||
public AsymCryptParams() => AfterCreate += () =>
|
public AsymCryptParams()
|
||||||
|
{
|
||||||
|
// init decryptors
|
||||||
|
AfterCreate += () =>
|
||||||
{
|
{
|
||||||
// Create root folder if it does not exist
|
// Create root folder if it does not exist
|
||||||
if (!Directory.Exists(PemDirectory))
|
if (!Directory.Exists(PemDirectory))
|
||||||
@@ -92,5 +98,19 @@ namespace DigitalData.Core.Security.Config
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// set signing credentials of token descriptions
|
||||||
|
AfterCreate += () =>
|
||||||
|
{
|
||||||
|
foreach(var tDesc in TokenDescriptions)
|
||||||
|
{
|
||||||
|
if (!Decryptors.TryGet(issuer: tDesc.Issuer, tDesc.Audience, out var decryptor) || decryptor is null)
|
||||||
|
throw new InvalidOperationException(
|
||||||
|
$"Decryptor for Issuer '{tDesc.Issuer}' and Audience '{tDesc.Audience}' could not be found or is null.");
|
||||||
|
|
||||||
|
tDesc.SigningCredentials = decryptor.CreateSigningCredentials(algorithm: tDesc.SigningAlgorithm, digest: tDesc.SigningDigest);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
11
DigitalData.Core.Security/Config/ClaimDescriptor.cs
Normal file
11
DigitalData.Core.Security/Config/ClaimDescriptor.cs
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
using System.Security.Claims;
|
||||||
|
|
||||||
|
namespace DigitalData.Core.Security.Config
|
||||||
|
{
|
||||||
|
public class ClaimDescriptor<TPrincipal>
|
||||||
|
{
|
||||||
|
public Func<TPrincipal, IDictionary<string, object>>? CreateClaims { get; init; }
|
||||||
|
|
||||||
|
public Func<TPrincipal, ClaimsIdentity>? CreateSubject { get; init; }
|
||||||
|
}
|
||||||
|
}
|
||||||
13
DigitalData.Core.Security/Config/MappingProfile.cs
Normal file
13
DigitalData.Core.Security/Config/MappingProfile.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
|
namespace DigitalData.Core.Security.Config
|
||||||
|
{
|
||||||
|
public class MappingProfile : Profile
|
||||||
|
{
|
||||||
|
public MappingProfile()
|
||||||
|
{
|
||||||
|
CreateMap<TokenDescription, SecurityTokenDescriptor>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
90
DigitalData.Core.Security/Config/TokenDescription.cs
Normal file
90
DigitalData.Core.Security/Config/TokenDescription.cs
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
|
namespace DigitalData.Core.Security.Config
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Contains some information which used to create a security token. Designed to abstract <see cref="SecurityTokenDescriptor"/>
|
||||||
|
/// </summary>
|
||||||
|
public class TokenDescription
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the value of the 'audience' claim.
|
||||||
|
/// </summary>
|
||||||
|
public string Audience { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Defines the compression algorithm that will be used to compress the JWT token payload.
|
||||||
|
/// </summary>
|
||||||
|
public string CompressionAlgorithm { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="EncryptingCredentials"/> used to create a encrypted security token.
|
||||||
|
/// </summary>
|
||||||
|
public EncryptingCredentials EncryptingCredentials { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the value of the 'expiration' claim. This value should be in UTC.
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? Expires { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the issuer of this <see cref="ITokenDescription"/>.
|
||||||
|
/// </summary>
|
||||||
|
public string Issuer { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the time the security token was issued. This value should be in UTC.
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? IssuedAt { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the notbefore time for the security token. This value should be in UTC.
|
||||||
|
/// </summary>
|
||||||
|
public DateTime? NotBefore { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the token type.
|
||||||
|
/// <remarks> If provided, this will be added as the value for the 'typ' header parameter. In the case of a JWE, this will be added to both the inner (JWS) and the outer token (JWE) header. By default, the value used is 'JWT'.
|
||||||
|
/// If <see cref="AdditionalHeaderClaims"/> also contains 'typ' header claim value, it will override the TokenType provided here.
|
||||||
|
/// This value is used only for JWT tokens and not for SAML/SAML2 tokens</remarks>
|
||||||
|
/// </summary>
|
||||||
|
public string TokenType { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="Dictionary{TKey, TValue}"/> which contains any custom header claims that need to be added to the JWT token header.
|
||||||
|
/// The 'alg', 'kid', 'x5t', 'enc', and 'zip' claims are added by default based on the <see cref="SigningCredentials"/>,
|
||||||
|
/// <see cref="EncryptingCredentials"/>, and/or <see cref="CompressionAlgorithm"/> provided and SHOULD NOT be included in this dictionary as this
|
||||||
|
/// will result in an exception being thrown.
|
||||||
|
/// <remarks> These claims are only added to the outer header (in case of a JWE).</remarks>
|
||||||
|
/// </summary>
|
||||||
|
public IDictionary<string, object> AdditionalHeaderClaims { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="Dictionary{TKey, TValue}"/> which contains any custom header claims that need to be added to the inner JWT token header.
|
||||||
|
/// The 'alg', 'kid', 'x5t', 'enc', and 'zip' claims are added by default based on the <see cref="SigningCredentials"/>,
|
||||||
|
/// <see cref="EncryptingCredentials"/>, and/or <see cref="CompressionAlgorithm"/> provided and SHOULD NOT be included in this dictionary as this
|
||||||
|
/// will result in an exception being thrown.
|
||||||
|
/// <remarks>
|
||||||
|
/// For JsonWebTokenHandler, these claims are merged with <see cref="AdditionalHeaderClaims"/> while adding to the inner JWT header.
|
||||||
|
/// </remarks>
|
||||||
|
/// </summary>
|
||||||
|
public IDictionary<string, object> AdditionalInnerHeaderClaims { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the <see cref="SigningCredentials"/> used to create a security token.
|
||||||
|
/// </summary>
|
||||||
|
public SigningCredentials SigningCredentials { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Specifies the signature algorithm to be applied to the <see cref="SigningCredentials"/>.
|
||||||
|
/// Default is <see cref="SecurityAlgorithms.RsaSha256"/>.
|
||||||
|
/// </summary>
|
||||||
|
public string SigningAlgorithm { get; init; } = SecurityAlgorithms.RsaSha256;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Optionally specifies the digest algorithm to be applied during the signing process for the <see cref="SigningCredentials"/>.
|
||||||
|
/// If not provided, the default algorithm is used.
|
||||||
|
/// </summary>
|
||||||
|
public string? SigningDigest = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
using DigitalData.Core.Abstractions.Security;
|
using DigitalData.Core.Abstractions.Security;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
@@ -24,8 +25,15 @@ namespace DigitalData.Core.Security.Cryptographer
|
|||||||
|
|
||||||
public string Audience { get; init; } = string.Empty;
|
public string Audience { get; init; } = string.Empty;
|
||||||
|
|
||||||
|
private readonly Lazy<RsaSecurityKey> _lazyRsaSecurityKey;
|
||||||
|
|
||||||
|
public RsaSecurityKey RsaSecurityKey => _lazyRsaSecurityKey.Value;
|
||||||
|
|
||||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||||
internal RSACryptographer() { }
|
internal RSACryptographer()
|
||||||
|
{
|
||||||
|
_lazyRsaSecurityKey = new(() => new RsaSecurityKey(RSA));
|
||||||
|
}
|
||||||
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
using DigitalData.Core.Abstractions.Security;
|
using DigitalData.Core.Abstractions.Security;
|
||||||
using DigitalData.Core.Security.Config;
|
using DigitalData.Core.Security.Config;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
using System.Security.Cryptography;
|
using System.Security.Cryptography;
|
||||||
|
|
||||||
namespace DigitalData.Core.Security.Cryptographer
|
namespace DigitalData.Core.Security.Cryptographer
|
||||||
@@ -59,5 +60,8 @@ namespace DigitalData.Core.Security.Cryptographer
|
|||||||
}
|
}
|
||||||
|
|
||||||
private InvalidOperationException PemIsNullException => new($"Pem is null or empty. Issuer: {Issuer}, Audience: {Audience}.");
|
private InvalidOperationException PemIsNullException => new($"Pem is null or empty. Issuer: {Issuer}, Audience: {Audience}.");
|
||||||
|
|
||||||
|
public SigningCredentials CreateSigningCredentials(string algorithm = SecurityAlgorithms.RsaSha256, string? digest = null)
|
||||||
|
=> digest is null ? new(RsaSecurityKey, algorithm) : new(RsaSecurityKey, algorithm, digest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,18 +4,40 @@ using DigitalData.Core.Security.Cryptographer;
|
|||||||
using Microsoft.Extensions.Configuration;
|
using Microsoft.Extensions.Configuration;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
|
using System.Security.Claims;
|
||||||
|
|
||||||
namespace DigitalData.Core.Security
|
namespace DigitalData.Core.Security
|
||||||
{
|
{
|
||||||
public static class DIExtensions
|
public static class DIExtensions
|
||||||
{
|
{
|
||||||
|
private static (bool Added, object Lock) _mappingProfile = (false, new());
|
||||||
|
private static IServiceCollection AddMappingProfile(this IServiceCollection services)
|
||||||
|
{
|
||||||
|
if (_mappingProfile.Added)
|
||||||
|
return services;
|
||||||
|
|
||||||
|
lock (_mappingProfile.Lock)
|
||||||
|
{
|
||||||
|
if (_mappingProfile.Added)
|
||||||
|
return services;
|
||||||
|
|
||||||
|
_mappingProfile.Added = true;
|
||||||
|
return services
|
||||||
|
.AddAutoMapper(typeof(MappingProfile).Assembly)
|
||||||
|
.AddSingleton<TokenDescriptorProvider>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static IServiceCollection AddParamsConfigureOptions<TParams>(this IServiceCollection services) where TParams : RSAFactoryParams
|
private static IServiceCollection AddParamsConfigureOptions<TParams>(this IServiceCollection services) where TParams : RSAFactoryParams
|
||||||
=> services.AddSingleton<IConfigureOptions<TParams>, ParamsConfigureOptions<TParams>>();
|
=> services.AddSingleton<IConfigureOptions<TParams>, ParamsConfigureOptions<TParams>>();
|
||||||
|
|
||||||
private static IServiceCollection AddAsymCryptService<TAsymCryptParams>(this IServiceCollection services, bool setAsDefault = false) where TAsymCryptParams : AsymCryptParams
|
private static IServiceCollection AddAsymCryptService<TAsymCryptParams>(this IServiceCollection services, bool setAsDefault = false) where TAsymCryptParams : AsymCryptParams
|
||||||
=> setAsDefault
|
{
|
||||||
? services.AddParamsConfigureOptions<TAsymCryptParams>().AddSingleton<IAsymCryptService, AsymCryptService<TAsymCryptParams>>()
|
services.AddParamsConfigureOptions<TAsymCryptParams>().AddMappingProfile();
|
||||||
: services.AddParamsConfigureOptions<TAsymCryptParams>().AddSingleton<IAsymCryptService<TAsymCryptParams>, AsymCryptService<TAsymCryptParams>>();
|
return setAsDefault
|
||||||
|
? services.AddSingleton<IAsymCryptService, AsymCryptService<TAsymCryptParams>>()
|
||||||
|
: services.AddSingleton<IAsymCryptService<TAsymCryptParams>, AsymCryptService<TAsymCryptParams>>();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers a custom asym crypt service with specified parameters from the given configuration section.
|
/// Registers a custom asym crypt service with specified parameters from the given configuration section.
|
||||||
@@ -38,7 +60,7 @@ namespace DigitalData.Core.Security
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static IServiceCollection AddAsymCryptService(this IServiceCollection services, IConfigurationSection section, bool setAsDefault = false)
|
public static IServiceCollection AddAsymCryptService(this IServiceCollection services, IConfigurationSection section, bool setAsDefault = false)
|
||||||
=> services.Configure<AsymCryptParams>(section).AddAsymCryptService<AsymCryptParams>(setAsDefault: setAsDefault);
|
=> services.Configure<AsymCryptParams>(section).AddAsymCryptService<AsymCryptParams>(setAsDefault: setAsDefault);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers an asym crypt service with the specified parameters from the given instance. Optionally, sets it as the default factory.
|
/// Registers an asym crypt service with the specified parameters from the given instance. Optionally, sets it as the default factory.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -68,8 +90,9 @@ namespace DigitalData.Core.Security
|
|||||||
/// <returns>The updated <see cref="IServiceCollection"/> with the RSA Factory registered.</returns>
|
/// <returns>The updated <see cref="IServiceCollection"/> with the RSA Factory registered.</returns>
|
||||||
public static IServiceCollection AddRSAFactory(this IServiceCollection services, RSAFactoryParams? factoryParams = null) => services
|
public static IServiceCollection AddRSAFactory(this IServiceCollection services, RSAFactoryParams? factoryParams = null) => services
|
||||||
.AddParamsConfigureOptions<RSAFactoryParams>()
|
.AddParamsConfigureOptions<RSAFactoryParams>()
|
||||||
|
.AddMappingProfile()
|
||||||
.AddScoped<IRSAFactory>(_ => new RSAFactory<RSAFactoryParams>(Options.Create(factoryParams ?? new())));
|
.AddScoped<IRSAFactory>(_ => new RSAFactory<RSAFactoryParams>(Options.Create(factoryParams ?? new())));
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Registers a custom RSA Factory with specified parameters from the given configuration section.
|
/// Registers a custom RSA Factory with specified parameters from the given configuration section.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -81,7 +104,7 @@ namespace DigitalData.Core.Security
|
|||||||
public static IServiceCollection AddRSAFactory<TRSAFactoryParams>(this IServiceCollection services, IConfigurationSection section, bool setAsDefault = false)
|
public static IServiceCollection AddRSAFactory<TRSAFactoryParams>(this IServiceCollection services, IConfigurationSection section, bool setAsDefault = false)
|
||||||
where TRSAFactoryParams : RSAFactoryParams
|
where TRSAFactoryParams : RSAFactoryParams
|
||||||
{
|
{
|
||||||
services.AddParamsConfigureOptions<TRSAFactoryParams>().Configure<TRSAFactoryParams>(section);
|
services.AddMappingProfile().AddParamsConfigureOptions<TRSAFactoryParams>().Configure<TRSAFactoryParams>(section);
|
||||||
return setAsDefault
|
return setAsDefault
|
||||||
? services.AddSingleton<IRSAFactory, RSAFactory<TRSAFactoryParams>>()
|
? services.AddSingleton<IRSAFactory, RSAFactory<TRSAFactoryParams>>()
|
||||||
: services.AddSingleton<IRSAFactory<TRSAFactoryParams>, RSAFactory<TRSAFactoryParams>>();
|
: services.AddSingleton<IRSAFactory<TRSAFactoryParams>, RSAFactory<TRSAFactoryParams>>();
|
||||||
@@ -98,10 +121,23 @@ namespace DigitalData.Core.Security
|
|||||||
public static IServiceCollection AddRSAFactory<TRSAFactoryParams>(this IServiceCollection services, TRSAFactoryParams rsaParams, bool setAsDefault = false)
|
public static IServiceCollection AddRSAFactory<TRSAFactoryParams>(this IServiceCollection services, TRSAFactoryParams rsaParams, bool setAsDefault = false)
|
||||||
where TRSAFactoryParams : RSAFactoryParams
|
where TRSAFactoryParams : RSAFactoryParams
|
||||||
{
|
{
|
||||||
services.AddSingleton(Options.Create(rsaParams));
|
services.AddMappingProfile().AddSingleton(Options.Create(rsaParams));
|
||||||
return setAsDefault
|
return setAsDefault
|
||||||
? services.AddParamsConfigureOptions<TRSAFactoryParams>().AddSingleton<IRSAFactory, RSAFactory<TRSAFactoryParams>>()
|
? services.AddParamsConfigureOptions<TRSAFactoryParams>().AddSingleton<IRSAFactory, RSAFactory<TRSAFactoryParams>>()
|
||||||
: services.AddParamsConfigureOptions<TRSAFactoryParams>().AddSingleton<IRSAFactory<TRSAFactoryParams>, RSAFactory<TRSAFactoryParams>>();
|
: services.AddParamsConfigureOptions<TRSAFactoryParams>().AddSingleton<IRSAFactory<TRSAFactoryParams>, RSAFactory<TRSAFactoryParams>>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static IServiceCollection AddClaimDescriptor<TPrincipal>(this IServiceCollection services,
|
||||||
|
Func<TPrincipal, IDictionary<string, object>>? claimsMapper = null,
|
||||||
|
Func<TPrincipal, ClaimsIdentity>? subjectMapper = null)
|
||||||
|
{
|
||||||
|
var descriptor = new ClaimDescriptor<TPrincipal>
|
||||||
|
{
|
||||||
|
CreateClaims = claimsMapper,
|
||||||
|
CreateSubject = subjectMapper
|
||||||
|
};
|
||||||
|
|
||||||
|
return services.AddSingleton(sp => Options.Create(descriptor));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<PackageReference Include="AutoMapper" Version="13.0.1" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Options.ConfigurationExtensions" Version="8.0.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
30
DigitalData.Core.Security/JwtSignatureService.cs
Normal file
30
DigitalData.Core.Security/JwtSignatureService.cs
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
using DigitalData.Core.Security.Config;
|
||||||
|
using Microsoft.Extensions.Options;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
using System.IdentityModel.Tokens.Jwt;
|
||||||
|
|
||||||
|
namespace DigitalData.Core.Security
|
||||||
|
{
|
||||||
|
public class JwtSignatureService<TPrincipal> : JwtSecurityTokenHandler
|
||||||
|
{
|
||||||
|
private readonly ClaimDescriptor<TPrincipal> _claimDescriptor;
|
||||||
|
|
||||||
|
private readonly TokenDescriptorProvider _descriptorProvider;
|
||||||
|
|
||||||
|
public JwtSignatureService(IOptions<ClaimDescriptor<TPrincipal>> claimDescriptorOptions, TokenDescriptorProvider descriptorProvider)
|
||||||
|
{
|
||||||
|
_claimDescriptor = claimDescriptorOptions.Value;
|
||||||
|
_descriptorProvider = descriptorProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SecurityToken CreateToken(TPrincipal subject, TokenDescription description)
|
||||||
|
{
|
||||||
|
var descriptor = _descriptorProvider.Create(description: description);
|
||||||
|
descriptor.Claims = _claimDescriptor.CreateClaims?.Invoke(subject);
|
||||||
|
descriptor.Subject = _claimDescriptor.CreateSubject?.Invoke(subject);
|
||||||
|
return CreateToken(descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string CreateAndWriteToken(TPrincipal subject, TokenDescription description) => WriteToken(CreateToken(subject, description));
|
||||||
|
}
|
||||||
|
}
|
||||||
19
DigitalData.Core.Security/TokenDescriptorProvider.cs
Normal file
19
DigitalData.Core.Security/TokenDescriptorProvider.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using AutoMapper;
|
||||||
|
using DigitalData.Core.Security.Config;
|
||||||
|
using Microsoft.IdentityModel.Tokens;
|
||||||
|
|
||||||
|
namespace DigitalData.Core.Security
|
||||||
|
{
|
||||||
|
public class TokenDescriptorProvider
|
||||||
|
{
|
||||||
|
private readonly IMapper _mapper;
|
||||||
|
|
||||||
|
public TokenDescriptorProvider(IMapper mapper)
|
||||||
|
{
|
||||||
|
_mapper = mapper;
|
||||||
|
}
|
||||||
|
|
||||||
|
public SecurityTokenDescriptor Create(TokenDescription description)
|
||||||
|
=> _mapper.Map(description, new SecurityTokenDescriptor());
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user