feat: harden SaaS authentication and authorization

This commit is contained in:
2026-07-28 12:15:51 +08:00
parent f22f329d33
commit 5d2248efee
123 changed files with 9090 additions and 2822 deletions

View File

@@ -0,0 +1,62 @@
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;
namespace Tiku.Infrastructure.Security;
public sealed class DataProtectionKeyRingOptions
{
public const string SectionName = "Security:DataProtection";
public string ApplicationName { get; set; } = "Tiku.Api";
public string CertificatePath { get; set; } = string.Empty;
public string CertificatePassword { get; set; } = string.Empty;
public static bool BeValid(DataProtectionKeyRingOptions options, bool requireCertificate)
{
return !string.IsNullOrWhiteSpace(options.ApplicationName) &&
(!requireCertificate || !string.IsNullOrWhiteSpace(options.CertificatePath));
}
public X509Certificate2? LoadCertificate(bool requireCertificate)
{
if (string.IsNullOrWhiteSpace(CertificatePath))
{
if (requireCertificate)
{
throw new InvalidOperationException(
"Data Protection certificate is required outside Development. " +
"Configure Security:DataProtection:CertificatePath or " +
"TIKU_DATA_PROTECTION_CERTIFICATE_PATH.");
}
return null;
}
try
{
var certificate = X509CertificateLoader.LoadPkcs12FromFile(
Path.GetFullPath(CertificatePath.Trim()),
CertificatePassword,
X509KeyStorageFlags.DefaultKeySet);
if (!certificate.HasPrivateKey)
{
certificate.Dispose();
throw new InvalidOperationException(
"Data Protection certificate must contain a private key.");
}
return certificate;
}
catch (InvalidOperationException)
{
throw;
}
catch (Exception exception) when (
exception is CryptographicException or IOException or UnauthorizedAccessException)
{
throw new InvalidOperationException(
"Data Protection certificate could not be loaded from the configured PKCS#12 file.",
exception);
}
}
}