共享 ASP.NET Core 3.1 启动和控制器中使用的配置对象的最佳方式是什么

What is the best way to share a Configuration object used in ASP.NET Core 3.1 Startup and Controllers

在 ASP.NET Core 3.1 Startup class 和控制器之间共享配置对象的最佳方式是什么?

我看过一些使用 DI 的示例,这似乎是个好主意,但我需要使用 public void ConfigureServices(IServiceCollection services) 中的依赖项。

此外,该对象依赖于一个 Microsoft.Extensions.Configuration.IConfiguration 实例。

The object will be used within Startup.cs, within the ConfigureServices itself as well as in Controllers.

DI 有用吗?还是解决方案是带参数的单例?

这里是需要分享的具体代码:

// openssl rand -hex 16 => 256 bits when read
var jwt_key = Configuration.GetSection("JwtOption:IssuerSigningKey").Value;
var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwt_key));

var tokenValidationParameters = new TokenValidationParameters
{
    // The signing key must match!
    ValidateIssuerSigningKey = true,
    IssuerSigningKey = signingKey,

    // Validate the JWT Issuer (iss) claim
    ValidateIssuer = true,
    ValidIssuer = "some host name",

    // Validate the JWT Audience (aud) claim
    ValidateAudience = true,
    ValidAudience = "web_intranet",

    // Validate the token expiry
    ValidateLifetime = true,

    // If you want to allow a certain amount of clock drift, set that here:
    ClockSkew = TimeSpan.Zero
};

此对象在 public void ConfigureServices(IServiceCollection services) 方法中使用如下

services
    .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
    .AddCookie(options =>
    {                
        options.TicketDataFormat = new CustomJwtDataFormat(
            SecurityAlgorithms.HmacSha256,
            tokenValidationParameters);
    });

尽量避免传递 IConfiguration。共享代码可以在 Startup 中完成,模型填充并添加到容器中

可以直接在Startup.ConfigureServices

中的容器中注册实例
void ConfigureServices(IServiceCollection services) {
    var jwt_key = Configuration.GetSection("JwtOption:IssuerSigningKey").Value;
    var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwt_key));

    var tokenValidationParameters = new TokenValidationParameters {
        //...code omitted for brevity
    }

    services.AddSingleton(tokenValidationParameters);

    //...can still use tokenValidationParameters

    services
        .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
        .AddCookie(options =>
        {                
            options.TicketDataFormat = new CustomJwtDataFormat(
                SecurityAlgorithms.HmacSha256,
                tokenValidationParameters);
        });
}

并在需要的地方显式注入

//ctr
public MyController(TokenValidationParameters tokenParameters) {

    //...

}

或者您可以使用选项模式

引用Options pattern in ASP.NET Core

void ConfigureServices(IServiceCollection services) {
    //...code omitted for brevity
    var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwt_key));

    services.Configure<TokenValidationParameters>(options => {    
        // The signing key must match!
        options.ValidateIssuerSigningKey = true;
        options.IssuerSigningKey = signingKey;

        // Validate the JWT Issuer (iss) claim
        options.ValidateIssuer = true;
        options.ValidIssuer = "some host name";

        // Validate the JWT Audience (aud) claim
        options.ValidateAudience = true;
        options.ValidAudience = "web_intranet";

        // Validate the token expiry
        options.ValidateLifetime = true;

        // If you want to allow a certain amount of clock drift, set that here:
        options.ClockSkew = TimeSpan.Zero;
    });

    //...

    //Use DI services to configure cookie options
    var scheme = CookieAuthenticationDefaults.AuthenticationScheme;
    services.AddOptions<CookieAuthenticationOptions>(scheme)
        .Configure<IOptions<TokenValidationParameters>>((options, token) => {
            options.TicketDataFormat = new CustomJwtDataFormat(
                SecurityAlgorithms.HmacSha256,
                token.Value); //<--
        });

    services
        .AddAuthentication(scheme)
        .AddCookie();
}

引用Use DI services to configure options

并在需要的地方注入 IOptions<TokenValidationParameters>

//ctr
public MyController(IOptions<TokenValidationParameters> options) {

    TokenValidationParameters tokenParameters = options.Value;

    //...

}

这是我使用 DI 测试的选项。

创建 POCO 对象:

public sealed class JwtConfig
{
    public TokenValidationParameters tokenValidationParameters;
    public JwtConfig(IConfiguration configuration)
    {
        // configure the object: tokenValidationParameters
    }
}

在启动中:

public void ConfigureServices(IServiceCollection services)
{
        // register
        services.AddSingleton<JwtConfig>();

        // retrieve 
        var serviceProvider = services.BuildServiceProvider();
        var jwtConfig = serviceProvider.GetService<JwtConfig>();

        // use the jwtConfig <IMPORTANT to be able to do this here>
}

在控制器构造函数中,注入对象:

    public LoginController(IUserService userService, JwtConfig jwtConfig)
    {
        this.jwtConfig = jwtConfig;
    }