12 changed files with 144 additions and 145 deletions
@ -0,0 +1,134 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Text; |
||||
|
using System.Threading.Tasks; |
||||
|
using CellularManagement.Domain.Options; |
||||
|
using CellularManagement.Domain.Services; |
||||
|
|
||||
|
namespace CellularManagement.Infrastructure.Services.Authentication; |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// JWT 验证服务实现
|
||||
|
/// </summary>
|
||||
|
public class JwtValidationService : IJwtValidationService |
||||
|
{ |
||||
|
/// <inheritdoc />
|
||||
|
public void ValidateOptions(JwtOptions options) |
||||
|
{ |
||||
|
if (string.IsNullOrEmpty(options.SecretKey)) |
||||
|
{ |
||||
|
throw new ArgumentException("JWT密钥不能为空"); |
||||
|
} |
||||
|
|
||||
|
if (string.IsNullOrEmpty(options.Issuer)) |
||||
|
{ |
||||
|
throw new ArgumentException("JWT颁发者不能为空"); |
||||
|
} |
||||
|
|
||||
|
if (string.IsNullOrEmpty(options.Audience)) |
||||
|
{ |
||||
|
throw new ArgumentException("JWT受众不能为空"); |
||||
|
} |
||||
|
|
||||
|
if (options.ExpiryMinutes <= 0) |
||||
|
{ |
||||
|
throw new ArgumentException("JWT过期时间必须大于0"); |
||||
|
} |
||||
|
|
||||
|
if (options.RefreshTokenExpiryDays <= 0) |
||||
|
{ |
||||
|
throw new ArgumentException("刷新令牌过期时间必须大于0"); |
||||
|
} |
||||
|
|
||||
|
if (options.ClockSkewMinutes < 0) |
||||
|
{ |
||||
|
throw new ArgumentException("时钟偏差不能为负数"); |
||||
|
} |
||||
|
|
||||
|
if (options.KeyRotationDays <= 0) |
||||
|
{ |
||||
|
throw new ArgumentException("密钥轮换间隔必须大于0"); |
||||
|
} |
||||
|
|
||||
|
if (options.MinKeyLength < 32) |
||||
|
{ |
||||
|
throw new ArgumentException("密钥最小长度必须至少为32字节"); |
||||
|
} |
||||
|
|
||||
|
// 验证密钥是否为有效的Base64字符串
|
||||
|
try |
||||
|
{ |
||||
|
var keyBytes = Convert.FromBase64String(options.SecretKey); |
||||
|
if (keyBytes.Length < options.MinKeyLength) |
||||
|
{ |
||||
|
throw new ArgumentException($"密钥长度必须至少为{options.MinKeyLength}字节"); |
||||
|
} |
||||
|
} |
||||
|
catch (FormatException) |
||||
|
{ |
||||
|
throw new ArgumentException("JWT密钥不是有效的Base64字符串"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
|
||||
|
/// <inheritdoc />
|
||||
|
public void ValidateKeyStrength(string secretKey, int minKeyLength) |
||||
|
{ |
||||
|
if (string.IsNullOrEmpty(secretKey)) |
||||
|
{ |
||||
|
throw new ArgumentException("密钥不能为空"); |
||||
|
} |
||||
|
|
||||
|
// 验证密钥是否为有效的Base64字符串
|
||||
|
try |
||||
|
{ |
||||
|
var keyBytes = Convert.FromBase64String(secretKey); |
||||
|
if (keyBytes.Length < minKeyLength) |
||||
|
{ |
||||
|
throw new ArgumentException($"密钥长度必须至少为 {minKeyLength} 字节"); |
||||
|
} |
||||
|
} |
||||
|
catch (FormatException) |
||||
|
{ |
||||
|
throw new ArgumentException("密钥不是有效的Base64字符串"); |
||||
|
} |
||||
|
|
||||
|
// 检查密钥是否包含足够的随机性
|
||||
|
var entropy = CalculateEntropy(secretKey); |
||||
|
if (entropy < 3.5) // 3.5 bits per character is considered good
|
||||
|
{ |
||||
|
throw new ArgumentException("密钥随机性不足"); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 计算字符串熵值
|
||||
|
/// </summary>
|
||||
|
private static double CalculateEntropy(string input) |
||||
|
{ |
||||
|
var charCounts = new Dictionary<char, int>(); |
||||
|
foreach (var c in input) |
||||
|
{ |
||||
|
if (charCounts.ContainsKey(c)) |
||||
|
{ |
||||
|
charCounts[c]++; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
charCounts[c] = 1; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
var length = input.Length; |
||||
|
var entropy = 0.0; |
||||
|
foreach (var count in charCounts.Values) |
||||
|
{ |
||||
|
var probability = (double)count / length; |
||||
|
entropy -= probability * Math.Log2(probability); |
||||
|
} |
||||
|
|
||||
|
return entropy; |
||||
|
} |
||||
|
} |
@ -1,7 +1,7 @@ |
|||||
using CellularManagement.Domain.Services; |
using CellularManagement.Domain.Services; |
||||
using Microsoft.Extensions.Caching.Memory; |
using Microsoft.Extensions.Caching.Memory; |
||||
|
|
||||
namespace CellularManagement.Infrastructure.Services; |
namespace CellularManagement.Infrastructure.Services.Infrastructure; |
||||
|
|
||||
/// <summary>
|
/// <summary>
|
||||
/// 内存缓存服务实现
|
/// 内存缓存服务实现
|
@ -1,135 +0,0 @@ |
|||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Linq; |
|
||||
using System.Text; |
|
||||
using System.Threading.Tasks; |
|
||||
using CellularManagement.Domain.Options; |
|
||||
using CellularManagement.Domain.Services; |
|
||||
|
|
||||
namespace CellularManagement.Infrastructure.Services |
|
||||
{ |
|
||||
/// <summary>
|
|
||||
/// JWT 验证服务实现
|
|
||||
/// </summary>
|
|
||||
public class JwtValidationService : IJwtValidationService |
|
||||
{ |
|
||||
/// <inheritdoc />
|
|
||||
public void ValidateOptions(JwtOptions options) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(options.SecretKey)) |
|
||||
{ |
|
||||
throw new ArgumentException("JWT密钥不能为空"); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(options.Issuer)) |
|
||||
{ |
|
||||
throw new ArgumentException("JWT颁发者不能为空"); |
|
||||
} |
|
||||
|
|
||||
if (string.IsNullOrEmpty(options.Audience)) |
|
||||
{ |
|
||||
throw new ArgumentException("JWT受众不能为空"); |
|
||||
} |
|
||||
|
|
||||
if (options.ExpiryMinutes <= 0) |
|
||||
{ |
|
||||
throw new ArgumentException("JWT过期时间必须大于0"); |
|
||||
} |
|
||||
|
|
||||
if (options.RefreshTokenExpiryDays <= 0) |
|
||||
{ |
|
||||
throw new ArgumentException("刷新令牌过期时间必须大于0"); |
|
||||
} |
|
||||
|
|
||||
if (options.ClockSkewMinutes < 0) |
|
||||
{ |
|
||||
throw new ArgumentException("时钟偏差不能为负数"); |
|
||||
} |
|
||||
|
|
||||
if (options.KeyRotationDays <= 0) |
|
||||
{ |
|
||||
throw new ArgumentException("密钥轮换间隔必须大于0"); |
|
||||
} |
|
||||
|
|
||||
if (options.MinKeyLength < 32) |
|
||||
{ |
|
||||
throw new ArgumentException("密钥最小长度必须至少为32字节"); |
|
||||
} |
|
||||
|
|
||||
// 验证密钥是否为有效的Base64字符串
|
|
||||
try |
|
||||
{ |
|
||||
var keyBytes = Convert.FromBase64String(options.SecretKey); |
|
||||
if (keyBytes.Length < options.MinKeyLength) |
|
||||
{ |
|
||||
throw new ArgumentException($"密钥长度必须至少为{options.MinKeyLength}字节"); |
|
||||
} |
|
||||
} |
|
||||
catch (FormatException) |
|
||||
{ |
|
||||
throw new ArgumentException("JWT密钥不是有效的Base64字符串"); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
|
|
||||
|
|
||||
/// <inheritdoc />
|
|
||||
public void ValidateKeyStrength(string secretKey, int minKeyLength) |
|
||||
{ |
|
||||
if (string.IsNullOrEmpty(secretKey)) |
|
||||
{ |
|
||||
throw new ArgumentException("密钥不能为空"); |
|
||||
} |
|
||||
|
|
||||
// 验证密钥是否为有效的Base64字符串
|
|
||||
try |
|
||||
{ |
|
||||
var keyBytes = Convert.FromBase64String(secretKey); |
|
||||
if (keyBytes.Length < minKeyLength) |
|
||||
{ |
|
||||
throw new ArgumentException($"密钥长度必须至少为 {minKeyLength} 字节"); |
|
||||
} |
|
||||
} |
|
||||
catch (FormatException) |
|
||||
{ |
|
||||
throw new ArgumentException("密钥不是有效的Base64字符串"); |
|
||||
} |
|
||||
|
|
||||
// 检查密钥是否包含足够的随机性
|
|
||||
var entropy = CalculateEntropy(secretKey); |
|
||||
if (entropy < 3.5) // 3.5 bits per character is considered good
|
|
||||
{ |
|
||||
throw new ArgumentException("密钥随机性不足"); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
/// <summary>
|
|
||||
/// 计算字符串熵值
|
|
||||
/// </summary>
|
|
||||
private static double CalculateEntropy(string input) |
|
||||
{ |
|
||||
var charCounts = new Dictionary<char, int>(); |
|
||||
foreach (var c in input) |
|
||||
{ |
|
||||
if (charCounts.ContainsKey(c)) |
|
||||
{ |
|
||||
charCounts[c]++; |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
charCounts[c] = 1; |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
var length = input.Length; |
|
||||
var entropy = 0.0; |
|
||||
foreach (var count in charCounts.Values) |
|
||||
{ |
|
||||
var probability = (double)count / length; |
|
||||
entropy -= probability * Math.Log2(probability); |
|
||||
} |
|
||||
|
|
||||
return entropy; |
|
||||
} |
|
||||
} |
|
||||
} |
|
@ -1,7 +1,7 @@ |
|||||
using CellularManagement.Domain.Services; |
using CellularManagement.Domain.Services; |
||||
using SkiaSharp; |
using SkiaSharp; |
||||
|
|
||||
namespace CellularManagement.Infrastructure.Services; |
namespace CellularManagement.Infrastructure.Services.Security; |
||||
|
|
||||
public class CaptchaService : ICaptchaService |
public class CaptchaService : ICaptchaService |
||||
{ |
{ |
Loading…
Reference in new issue