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

如何通过依赖注入(DI)配置OpenIddict加密密钥以对接Azure Key Vault?

如何通过合规的依赖注入方式配置OpenIddict的Azure Key Vault密钥

你提到的手动调用BuildServiceProvider()确实是反模式,会导致单例服务重复实例化,完全不推荐。好在OpenIddict和ASP.NET Core的选项系统提供了几种合规的方式来实现你的需求,下面分场景详细说明:

方法1:使用OpenIddict内置的工厂函数重载

OpenIddict的AddSigningKey(服务器端)和AddEncryptionKey(验证端)都提供了接受Func<IServiceProvider, SecurityKey>的重载,这个工厂函数会在服务提供者完全构建完成后才被调用,因此可以安全地从DI容器中解析所需服务:

服务器端(签名密钥配置)

public void ConfigureServices(IServiceCollection services)
{
    // 先注册你的Azure Key Vault客户端服务
    services.AddSingleton<IAzureKeyVaultClient>(provider => 
    {
        // 根据实际情况初始化客户端,比如用Azure.Identity的DefaultAzureCredential
        return new AzureKeyVaultClient(new DefaultAzureCredential());
    });

    services.AddOpenIddict()
        .AddServer(options =>
        {
            // 配置OpenIddict服务器基础选项(端点、令牌类型等)
            options.SetAuthorizationEndpoint("/connect/authorize")
                   .SetTokenEndpoint("/connect/token")
                   .AllowAuthorizationCodeFlow();

            // 延迟获取Azure Key Vault中的密钥
            options.AddSigningKey(async provider =>
            {
                var keyVaultClient = provider.GetRequiredService<IAzureKeyVaultClient>();
                // 替换为你的密钥名称和Key Vault URI
                var keyBundle = await keyVaultClient.GetKeyAsync("https://your-keyvault.vault.azure.net/keys/your-signing-key");
                var rsaKey = keyBundle.Key.ToRSA();
                
                return new RsaSecurityKey(rsaKey);
            });
        });
}

资源API端(验证加密密钥配置)

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IAzureKeyVaultClient>(provider => 
    {
        return new AzureKeyVaultClient(new DefaultAzureCredential());
    });

    services.AddOpenIddict()
        .AddValidation(options =>
        {
            // 配置验证选项,比如设置颁发者地址
            options.SetIssuer("https://your-authorization-server.com");
            options.UseLocalServer();

            // 同样用工厂函数获取密钥
            options.AddEncryptionKey(async provider =>
            {
                var keyVaultClient = provider.GetRequiredService<IAzureKeyVaultClient>();
                var keyBundle = await keyVaultClient.GetKeyAsync("https://your-keyvault.vault.azure.net/keys/your-encryption-key");
                var rsaKey = keyBundle.Key.ToRSA();
                
                return new RsaSecurityKey(rsaKey);
            });
        });
}

方法2:使用ASP.NET Core选项系统的PostConfigure

如果你更倾向于遵循ASP.NET Core的配置惯例,可以用PostConfigure来延迟配置OpenIddict选项,它允许你直接注入所需的服务,完全不需要手动处理服务提供者:

服务器端示例

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IAzureKeyVaultClient>(provider => 
    {
        return new AzureKeyVaultClient(new DefaultAzureCredential());
    });

    // 先注册OpenIddict服务器的基础配置
    services.AddOpenIddict()
        .AddServer(options =>
        {
            options.SetAuthorizationEndpoint("/connect/authorize")
                   .SetTokenEndpoint("/connect/token")
                   .AllowAuthorizationCodeFlow();
            // 暂时不添加密钥,留到PostConfigure处理
        });

    // 注入Azure Key Vault客户端并配置签名密钥
    services.AddOptions<OpenIddictServerOptions>()
        .PostConfigure<IAzureKeyVaultClient>(async (options, keyVaultClient) =>
        {
            var keyBundle = await keyVaultClient.GetKeyAsync("https://your-keyvault.vault.azure.net/keys/your-signing-key");
            var rsaKey = keyBundle.Key.ToRSA();
            
            options.AddSigningKey(new RsaSecurityKey(rsaKey));
        });
}

资源API端示例

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IAzureKeyVaultClient>(provider => 
    {
        return new AzureKeyVaultClient(new DefaultAzureCredential());
    });

    services.AddOpenIddict()
        .AddValidation(options =>
        {
            options.SetIssuer("https://your-authorization-server.com");
            options.UseLocalServer();
        });

    services.AddOptions<OpenIddictValidationOptions>()
        .PostConfigure<IAzureKeyVaultClient>(async (options, keyVaultClient) =>
        {
            var keyBundle = await keyVaultClient.GetKeyAsync("https://your-keyvault.vault.azure.net/keys/your-encryption-key");
            var rsaKey = keyBundle.Key.ToRSA();
            
            options.AddEncryptionKey(new RsaSecurityKey(rsaKey));
        });
}

方法3:自定义密钥提供者(支持密钥自动轮转)

如果你的Azure Key Vault密钥需要定期轮转,上面的方法只会在启动时获取一次密钥,无法自动更新。这种情况下,你可以实现OpenIddict的ISigningKeyProvider(服务器端)或IValidationEncryptionKeyProvider(验证端)接口,OpenIddict会定期调用这个提供者来获取最新密钥:

自定义签名密钥提供者

public class AzureKeyVaultSigningKeyProvider : ISigningKeyProvider
{
    private readonly IAzureKeyVaultClient _keyVaultClient;
    private readonly string _keyIdentifier;

    public AzureKeyVaultSigningKeyProvider(IAzureKeyVaultClient keyVaultClient, IConfiguration configuration)
    {
        _keyVaultClient = keyVaultClient;
        _keyIdentifier = configuration["OpenIddict:SigningKeyIdentifier"];
    }

    public async ValueTask<IEnumerable<SecurityKey>> GetSigningKeysAsync(CancellationToken cancellationToken)
    {
        var keyBundle = await _keyVaultClient.GetKeyAsync(_keyIdentifier, cancellationToken: cancellationToken);
        var rsaKey = keyBundle.Key.ToRSA();
        
        return new[] { new RsaSecurityKey(rsaKey) };
    }
}

注册并使用自定义提供者

public void ConfigureServices(IServiceCollection services)
{
    services.AddSingleton<IAzureKeyVaultClient>(provider => 
    {
        return new AzureKeyVaultClient(new DefaultAzureCredential());
    });

    // 注册自定义密钥提供者
    services.AddSingleton<ISigningKeyProvider, AzureKeyVaultSigningKeyProvider>();

    services.AddOpenIddict()
        .AddServer(options =>
        {
            options.SetAuthorizationEndpoint("/connect/authorize")
                   .SetTokenEndpoint("/connect/token")
                   .AllowAuthorizationCodeFlow();

            // 启用使用自定义密钥提供者
            options.UseSigningKeyProvider();
        });
}

这种方式的优势在于,OpenIddict会根据配置的刷新间隔(默认24小时)自动调用GetSigningKeysAsync获取最新密钥,无需重启应用就能支持密钥轮转。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.27 21:47:42