Search code examples
c#asp.net-coreasp.net-core-configuration

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


What is the best way to share a configuration object between the ASP.NET Core 3.1 Startup class and Controllers?

I have seen some examples using DI, and this seems like a good idea, but I need to use the dependency within public void ConfigureServices(IServiceCollection services).

Furthermore the object depends on a Microsoft.Extensions.Configuration.IConfiguration instance.

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

Would DI work? Or is the solution a Singleton with parameters?

Here is the specific code that needs to be shared:

// 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
};

This object is used as follows within the public void ConfigureServices(IServiceCollection services) method

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

Solution

  • Try to avoid passing IConfiguration around. The shared code can be done in Startup and the model populated and added to the container

    You can register the instance directly with the container in 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);
            });
    }
    

    and inject it explicitly where needed

    //ctr
    public MyController(TokenValidationParameters tokenParameters) {
    
        //...
    
    }
    

    Or you can use options pattern

    Reference 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();
    }
    

    Reference Use DI services to configure options

    and Inject IOptions<TokenValidationParameters> where needed

    //ctr
    public MyController(IOptions<TokenValidationParameters> options) {
    
        TokenValidationParameters tokenParameters = options.Value;
    
        //...
    
    }