Reputation: 36770
Is there a good way to get the ServiceProvider
in the AddOpenIdConnect
, or configure the ClientSecret later where we have the DI container fully setup? (e.g. in Configure(IApplicationBuilder app)
)
We're getting the client secret from somewhere else and we like to use DI for that.
Currently we do this, but I really like to remove services.BuildServiceProvider()
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddOpenIdConnect(AuthenticationScheme, options =>
{
ServiceProvider serviceProvider = services.BuildServiceProvider(); // we like to prevent this
options.ClientSecret = serviceProvider.GetRequiredService<ISecretRetriever>().GetClientSecret();
For events like OnValidatePrincipal
we could get it from CookieValidatePrincipalContext.HttpContext.RequestServices
Using services.BuildServiceProvider()
will give this warning:
warning "Calling 'BuildServiceProvider' from application code results in a additional copy of Singleton services being created"
Upvotes: 8
Views: 1961
Reputation: 175
To build off of Kirk's answer for a fuller example
// Register our custom options -- we can resolve this as IOptions<MyCustomOptions>
services.Configure<MyCustomOptions>(config.GetSection(optionsSection));
// Configure OIDC
var authBuilder = services.AddAuthentication()
.AddOpenIdConnect(schemeName, options => ...);
// Update OIDC config with our custom options
authBuilder.Services.AddOptions<OpenIdConnectOptions>(schemeName)
.Configure<IOptions<MyCustomOptions>>((oidcOptions, myOptions) =>
{
oidcOptions.ClientSecret = myOptions.Value.SecretTime;
});
// register some other services
builder.Services.AddSingleton<Foo>(sp => {
var myOpts = sp.GetRequiredService<IOptions<MyCustomOptions>>();
new Foo(myOpts.Value.SecretTime)
};
Upvotes: 0
Reputation: 93193
The configuration system for authentication uses the Options pattern. This means that the following approach would have a similar effect to the approach shown in your question:
services.AddAuthentication()
.AddOpenIdConnect(AuthenticationScheme, options =>
{
// ...
});
services.Configure<OpenIdConnectOptions>(AuthenticationScheme, options =>
{
options.ClientSecret = "ClientSecret";
});
This is useful because the options pattern supports DI, using something like the following:
services.AddOptions<OpenIdConnectOptions>(AuthenticationScheme)
.Configure<ISecretRetriever>((options, secretRetriever) =>
{
options.ClientSecret = secretRetriever.GetClientSecret();
});
To get access to the Configure
method that works with DI, you must first call AddOptions
. In this example, Configure
is given a single type argument, which represents the dependency that's needed. This is passed into your configuration callback as the second parameter, after the OpenIdConnectOptions
instance that's being configured.
Upvotes: 8