You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在关系数据库(如Postgres)存储RsaSecurityKey用于IdentityServer4签名JWT

Got it, let's walk through this step by step—creating an RsaSecurityKey, storing it in PostgreSQL, and using it with IdentityServer4 to sign JWT tokens is totally doable with a few clear steps. Here's how to pull it off:

Step 1: Generate an RSA Key Pair and Extract Parameters

First, you can't serialize the RsaSecurityKey object directly to a database—you need to pull out its underlying RSA parameters. Use the built-in RSA class to generate a secure key pair:

using System.Security.Cryptography;
using System.IdentityModel.Tokens.Jwt;

// Generate a 2048-bit RSA key pair (4096-bit is better for high-security scenarios)
using var rsa = RSA.Create(2048);

// Export full key parameters (including private key components)
var rsaParams = rsa.ExportParameters(includePrivateParameters: true);

// These are the values you'll store in PostgreSQL:
// rsaParams.Modulus, Exponent (public key parts)
// rsaParams.D, P, Q, DP, DQ, InverseQ (private key parts)
Step 2: Set Up PostgreSQL to Store Key Parameters

Create a table to hold your signing keys—use bytea for binary parameter fields, and add metadata to track active keys and rotation:

CREATE TABLE signing_keys (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    key_id VARCHAR(255) UNIQUE NOT NULL, -- Used as the "kid" in JWT headers
    modulus BYTEA NOT NULL,
    exponent BYTEA NOT NULL,
    d BYTEA NOT NULL, -- Private key component
    p BYTEA NOT NULL, -- Private key component
    q BYTEA NOT NULL, -- Private key component
    dp BYTEA NOT NULL, -- Private key component
    dq BYTEA NOT NULL, -- Private key component
    inverse_q BYTEA NOT NULL, -- Private key component
    created_at TIMESTAMPTZ DEFAULT NOW(),
    is_active BOOLEAN DEFAULT true
);

-- Optional: Index for fast active key lookup
CREATE INDEX idx_signing_keys_active ON signing_keys(is_active);

If you're using Entity Framework Core, here's the matching entity class:

public class SigningKey
{
    public Guid Id { get; set; } = Guid.NewGuid();
    public string KeyId { get; set; } = Guid.NewGuid().ToString(); // Unique "kid" identifier
    public byte[] Modulus { get; set; }
    public byte[] Exponent { get; set; }
    public byte[] D { get; set; }
    public byte[] P { get; set; }
    public byte[] Q { get; set; }
    public byte[] DP { get; set; }
    public byte[] DQ { get; set; }
    public byte[] InverseQ { get; set; }
    public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
    public bool IsActive { get; set; } = true;
}

Insert your generated key parameters into the database:

// Assuming you have a DbContext with a DbSet<SigningKey>
var newSigningKey = new SigningKey
{
    KeyId = "prod-signing-key-2024-v1", // Use a meaningful, unique ID
    Modulus = rsaParams.Modulus,
    Exponent = rsaParams.Exponent,
    D = rsaParams.D,
    P = rsaParams.P,
    Q = rsaParams.Q,
    DP = rsaParams.DP,
    DQ = rsaParams.DQ,
    InverseQ = rsaParams.InverseQ
};

await dbContext.SigningKeys.AddAsync(newSigningKey);
await dbContext.SaveChangesAsync();
Step 3: Retrieve and Reconstruct the RsaSecurityKey

When IdentityServer needs to sign tokens, fetch the active key from the database and rebuild the RsaSecurityKey:

private async Task<RsaSecurityKey> GetActiveSigningKeyAsync(AppDbContext dbContext)
{
    // Fetch the currently active signing key
    var storedKey = await dbContext.SigningKeys
        .Where(k => k.IsActive)
        .FirstOrDefaultAsync();

    if (storedKey == null)
        throw new InvalidOperationException("No active signing key found in the database");

    // Reconstruct RSA parameters from stored values
    var rsaParams = new RSAParameters
    {
        Modulus = storedKey.Modulus,
        Exponent = storedKey.Exponent,
        D = storedKey.D,
        P = storedKey.P,
        Q = storedKey.Q,
        DP = storedKey.DP,
        DQ = storedKey.DQ,
        InverseQ = storedKey.InverseQ
    };

    // Create RSA instance and import parameters
    using var rsa = RSA.Create();
    rsa.ImportParameters(rsaParams);

    // Build RsaSecurityKey with matching KeyId (for JWT header "kid")
    return new RsaSecurityKey(rsa) { KeyId = storedKey.KeyId };
}
Step 4: Configure IdentityServer4 to Use the Stored Key

Update your IdentityServer4 setup to use this database-backed key instead of the default development key. In Program.cs:

builder.Services.AddIdentityServer()
    .AddInMemoryClients(Config.Clients) // Replace with your client config
    .AddInMemoryApiScopes(Config.ApiScopes) // Replace with your API scopes
    .AddInMemoryIdentityResources(Config.IdentityResources) // Replace with your identity resources
    .AddAspNetIdentity<ApplicationUser>() // If using ASP.NET Identity
    .AddSigningCredential(await GetActiveSigningKeyAsync(builder.Services.BuildServiceProvider().GetRequiredService<AppDbContext>()));

For better performance (to avoid repeated database calls), register the signing key as a singleton:

builder.Services.AddSingleton<ISigningCredentialStore>(async sp =>
{
    var dbContext = sp.GetRequiredService<AppDbContext>();
    var securityKey = await GetActiveSigningKeyAsync(dbContext);
    
    // Use RS256 (RSA-SHA256) for secure signing
    var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.RsaSha256);
    return new InMemorySigningCredentialsStore(credentials);
});
Critical Best Practices
  • Encrypt Private Key Data: Never store private key parameters (D, P, Q, etc.) in plaintext. Use PostgreSQL's pgcrypto extension to encrypt these fields at rest, or use a secret manager like Azure Key Vault/HashiCorp Vault instead of direct database storage.
  • Key Rotation: Implement key rotation by adding new keys to the database and marking them as active. Keep old keys to validate existing tokens until they expire.
  • Cache the Key: In production, cache the active signing key to avoid hitting the database on every token request.
  • Use Strong Algorithms: Stick to RsaSha256 or RsaSha512—avoid outdated algorithms like SHA1.

内容的提问来源于stack exchange,提问作者dudedev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:12:40