Compare commits
No commits in common. "d2ef99d0b29cbfc3036b4029b52ffafdb4e82011" and "62a859b44c550627b0c92d899ac32c55b8a205a5" have entirely different histories.
d2ef99d0b2
...
62a859b44c
@ -1,82 +0,0 @@
|
|||||||
using Microsoft.IdentityModel.Tokens;
|
|
||||||
using Mirea.Api.Security.Common.Interfaces;
|
|
||||||
using System;
|
|
||||||
using System.IdentityModel.Tokens.Jwt;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Security.Claims;
|
|
||||||
|
|
||||||
namespace Mirea.Api.Endpoint.Common.Services.Security;
|
|
||||||
|
|
||||||
public class JwtTokenService : IAccessToken
|
|
||||||
{
|
|
||||||
public required string Issuer { private get; init; }
|
|
||||||
public required string Audience { private get; init; }
|
|
||||||
public TimeSpan Lifetime { private get; init; }
|
|
||||||
|
|
||||||
public ReadOnlyMemory<byte> EncryptionKey { get; init; }
|
|
||||||
public ReadOnlyMemory<byte> SigningKey { private get; init; }
|
|
||||||
|
|
||||||
public (string Token, DateTime ExpireIn) GenerateToken(string userId)
|
|
||||||
{
|
|
||||||
var tokenHandler = new JwtSecurityTokenHandler();
|
|
||||||
var signingKey = new SymmetricSecurityKey(SigningKey.ToArray());
|
|
||||||
var encryptionKey = new SymmetricSecurityKey(EncryptionKey.ToArray());
|
|
||||||
var signingCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha512);
|
|
||||||
|
|
||||||
var expires = DateTime.UtcNow.Add(Lifetime);
|
|
||||||
|
|
||||||
var tokenDescriptor = new SecurityTokenDescriptor
|
|
||||||
{
|
|
||||||
Issuer = Issuer,
|
|
||||||
Audience = Audience,
|
|
||||||
Expires = expires,
|
|
||||||
SigningCredentials = signingCredentials,
|
|
||||||
Subject = new ClaimsIdentity(
|
|
||||||
[
|
|
||||||
new Claim(ClaimTypes.Name, userId),
|
|
||||||
// todo: get role by userId
|
|
||||||
new Claim(ClaimTypes.Role, "")
|
|
||||||
]),
|
|
||||||
EncryptingCredentials = new EncryptingCredentials(encryptionKey, SecurityAlgorithms.Aes256KW, SecurityAlgorithms.Aes256CbcHmacSha512)
|
|
||||||
};
|
|
||||||
|
|
||||||
var token = tokenHandler.CreateToken(tokenDescriptor);
|
|
||||||
|
|
||||||
return (tokenHandler.WriteToken(token), expires);
|
|
||||||
}
|
|
||||||
|
|
||||||
public DateTimeOffset GetExpireDateTime(string token)
|
|
||||||
{
|
|
||||||
var tokenHandler = new JwtSecurityTokenHandler();
|
|
||||||
var signingKey = new SymmetricSecurityKey(SigningKey.ToArray());
|
|
||||||
var encryptionKey = new SymmetricSecurityKey(EncryptionKey.ToArray());
|
|
||||||
|
|
||||||
var tokenValidationParameters = new TokenValidationParameters
|
|
||||||
{
|
|
||||||
ValidIssuer = Issuer,
|
|
||||||
ValidAudience = Audience,
|
|
||||||
IssuerSigningKey = signingKey,
|
|
||||||
TokenDecryptionKey = encryptionKey,
|
|
||||||
ValidateIssuer = true,
|
|
||||||
ValidateAudience = true,
|
|
||||||
ValidateIssuerSigningKey = true,
|
|
||||||
ValidateLifetime = false
|
|
||||||
};
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var claimsPrincipal = tokenHandler.ValidateToken(token, tokenValidationParameters, out _);
|
|
||||||
|
|
||||||
var expClaim = claimsPrincipal.Claims.FirstOrDefault(c => c.Type == "exp");
|
|
||||||
|
|
||||||
if (expClaim != null && long.TryParse(expClaim.Value, out var expUnix))
|
|
||||||
return DateTimeOffset.FromUnixTimeSeconds(expUnix);
|
|
||||||
}
|
|
||||||
catch (SecurityTokenException)
|
|
||||||
{
|
|
||||||
return DateTimeOffset.MinValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return DateTimeOffset.MinValue;
|
|
||||||
}
|
|
||||||
}
|
|
@ -23,10 +23,9 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Cronos" Version="0.8.4" />
|
<PackageReference Include="Cronos" Version="0.8.4" />
|
||||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.6" />
|
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
|
||||||
<PackageReference Include="StackExchange.Redis" Version="2.7.33" />
|
<PackageReference Include="StackExchange.Redis" Version="2.7.33" />
|
||||||
<PackageReference Include="Swashbuckle.AspNetCore.Versioning" Version="2.0.0" />
|
<PackageReference Include="Swashbuckle.AspNetCore.Versioning" Version="2.0.0" />
|
||||||
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="7.6.0" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
|
||||||
using Microsoft.AspNetCore.Builder;
|
using Microsoft.AspNetCore.Builder;
|
||||||
using Microsoft.AspNetCore.Mvc;
|
using Microsoft.AspNetCore.Mvc;
|
||||||
using Microsoft.AspNetCore.Mvc.ApiExplorer;
|
using Microsoft.AspNetCore.Mvc.ApiExplorer;
|
||||||
@ -7,24 +6,20 @@ using Microsoft.Extensions.Configuration;
|
|||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using Microsoft.Extensions.Hosting;
|
using Microsoft.Extensions.Hosting;
|
||||||
using Microsoft.Extensions.Options;
|
using Microsoft.Extensions.Options;
|
||||||
using Microsoft.IdentityModel.Tokens;
|
|
||||||
using Mirea.Api.DataAccess.Application;
|
using Mirea.Api.DataAccess.Application;
|
||||||
using Mirea.Api.DataAccess.Persistence;
|
using Mirea.Api.DataAccess.Persistence;
|
||||||
using Mirea.Api.Endpoint.Common.Interfaces;
|
using Mirea.Api.Endpoint.Common.Interfaces;
|
||||||
using Mirea.Api.Endpoint.Common.Services;
|
using Mirea.Api.Endpoint.Common.Services;
|
||||||
using Mirea.Api.Endpoint.Common.Services.Security;
|
|
||||||
using Mirea.Api.Endpoint.Configuration;
|
using Mirea.Api.Endpoint.Configuration;
|
||||||
using Mirea.Api.Endpoint.Configuration.General;
|
using Mirea.Api.Endpoint.Configuration.General;
|
||||||
using Mirea.Api.Endpoint.Configuration.General.Validators;
|
using Mirea.Api.Endpoint.Configuration.General.Validators;
|
||||||
using Mirea.Api.Endpoint.Configuration.Swagger;
|
using Mirea.Api.Endpoint.Configuration.Swagger;
|
||||||
using Mirea.Api.Endpoint.Middleware;
|
using Mirea.Api.Endpoint.Middleware;
|
||||||
using Mirea.Api.Security.Common.Interfaces;
|
|
||||||
using Swashbuckle.AspNetCore.SwaggerGen;
|
using Swashbuckle.AspNetCore.SwaggerGen;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
|
|
||||||
namespace Mirea.Api.Endpoint;
|
namespace Mirea.Api.Endpoint;
|
||||||
|
|
||||||
@ -45,66 +40,6 @@ public class Program
|
|||||||
return result.Build();
|
return result.Build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static IServiceCollection ConfigureJwtToken(IServiceCollection services, IConfiguration configuration)
|
|
||||||
{
|
|
||||||
var lifeTimeJwt = TimeSpan.FromMinutes(int.Parse(configuration["SECURITY_LIFE_TIME_JWT"]!));
|
|
||||||
|
|
||||||
var jwtDecrypt = Encoding.UTF8.GetBytes(configuration["SECURITY_ENCRYPTION_TOKEN"] ?? string.Empty);
|
|
||||||
|
|
||||||
if (jwtDecrypt.Length != 32)
|
|
||||||
throw new InvalidOperationException("The secret token \"SECURITY_ENCRYPTION_TOKEN\" cannot be less than 32 characters long. Now the size is equal is " + jwtDecrypt.Length);
|
|
||||||
|
|
||||||
var jwtKey = Encoding.UTF8.GetBytes(configuration["SECURITY_SIGNING_TOKEN"] ?? string.Empty);
|
|
||||||
|
|
||||||
if (jwtKey.Length != 64)
|
|
||||||
throw new InvalidOperationException("The signature token \"SECURITY_SIGNING_TOKEN\" cannot be less than 64 characters. Now the size is " + jwtKey.Length);
|
|
||||||
|
|
||||||
var jwtIssuer = configuration["SECURITY_JWT_ISSUER"];
|
|
||||||
var jwtAudience = configuration["SECURITY_JWT_AUDIENCE"];
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(jwtAudience) || string.IsNullOrEmpty(jwtIssuer))
|
|
||||||
throw new InvalidOperationException("The \"SECURITY_JWT_ISSUER\" and \"SECURITY_JWT_AUDIENCE\" are not specified");
|
|
||||||
|
|
||||||
services.AddSingleton<IAccessToken, JwtTokenService>(_ => new JwtTokenService
|
|
||||||
{
|
|
||||||
Audience = jwtAudience,
|
|
||||||
Issuer = jwtIssuer,
|
|
||||||
Lifetime = lifeTimeJwt,
|
|
||||||
EncryptionKey = jwtDecrypt,
|
|
||||||
SigningKey = jwtKey
|
|
||||||
});
|
|
||||||
|
|
||||||
services.AddAuthentication(options =>
|
|
||||||
{
|
|
||||||
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
||||||
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
|
|
||||||
}).AddJwtBearer(options =>
|
|
||||||
{
|
|
||||||
options.TokenValidationParameters = new TokenValidationParameters
|
|
||||||
{
|
|
||||||
ValidateIssuer = true,
|
|
||||||
ValidIssuer = jwtIssuer,
|
|
||||||
|
|
||||||
ValidateAudience = true,
|
|
||||||
ValidAudience = jwtAudience,
|
|
||||||
|
|
||||||
ValidateLifetime = true,
|
|
||||||
ValidateIssuerSigningKey = true,
|
|
||||||
IssuerSigningKey = new SymmetricSecurityKey(jwtKey),
|
|
||||||
TokenDecryptionKey = new SymmetricSecurityKey(jwtDecrypt)
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return services;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IServiceCollection ConfigureSecurity(IServiceCollection services)
|
|
||||||
{
|
|
||||||
services.AddSingleton<IAccessToken, JwtTokenService>();
|
|
||||||
services.AddSingleton<IRevokedToken, MemoryRevokedTokenService>();
|
|
||||||
|
|
||||||
return services;
|
|
||||||
}
|
|
||||||
public static void Main(string[] args)
|
public static void Main(string[] args)
|
||||||
{
|
{
|
||||||
Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
|
Directory.SetCurrentDirectory(AppDomain.CurrentDomain.BaseDirectory);
|
||||||
|
Loading…
Reference in New Issue
Block a user