I can't find a way how to migrate the application from aspnet core 1.1 to 2.0 which is using cookie authentication.
Most useful resources I already know are:
https://learn.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/identity-2x#cookie-based-authentication
https://github.com/aspnet/announcements/issues/262
https://github.com/aspnet/Home/issues/2128 (my own question)
Unfortunately, I am still stuck. Here is how I do it:
In Startup.cs ConfigureServices(IServiceCollection services)I have:
services.AddSingleton<IConfigureNamedOptions<CookieAuthenticationOptions>, CookieAuthenticationOptionsSetup>();
and later:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie();
The CookieAuthenticationOptionsSetup class implements IConfigureNamedOptions and sets options.Cookie.Name = "test" inside the Configure method.
I event tried to manually create and set Name property to "Cookies".
If I try to change the name of cookie with lambda expression inside Startup.cs AddCookie method, it works as expected. But if I don't, the CookieAuthenticationOptionsSetup is never used and the default cookie name (.AspNetCore.Cookies) is used.
What I am missing?
AddCookie() by default calls AuthenticationBuilder.AddScheme. From there, we can learn how the options would be ideally registered if you passed them to the AddCookie call:
Services.Configure(authenticationScheme, configureOptions);
So let’s take a look at how Services.Configure works with named options. What ultimately gets registered on the service collection are IConfigureOptions<CookieAuthenticationOptions>>.
So I would guess that is the exact type that is being looked up later when the options are resolved via DI. And in fact, that is the exact type that is being request by the OptionsFactory that is being used by the OptionsMonitor which is requested by the authentication handler.
So, tl;dr: You are registering your custom configuration as the wrong type. You should register it as an IConfigureOptions<>:
services.AddSingleton<IConfigureOptions<CookieAuthenticationOptions>, CookieAuthenticationOptionsSetup>();
Note of course that your CookieAuthenticationOptionsSetup needs to implement IConfigureNamedOptions properly and respond to a Configure call with your scheme name (CookieAuthenticationDefaults.AuthenticationScheme).
In addition to this answer, I also had to add Name property to the class which implements IConfigureNamedOptions<T> and set it in public void Configure(string name, CookieAuthenticationOptions options) method.
Few additional notes for those who will have the same problem:
To apply Authorize attribute globally, authentication scheme must be added (worked without it previously):
services.AddMvcCore(a =>
{
var policy = new AuthorizationPolicyBuilder().AddAuthenticationSchemes(CookieAuthenticationDefaults.AuthenticationScheme).RequireAuthenticatedUser().Build();
a.Filters.Add(new AuthorizeFilter(policy));
});
To use IsAuthenticated property inside middleware, app.UseAuthentication() must be called before registering the middleware.
It is not exactly clear what is the question...
But if you want just to set cookie name (or other options) and really do not need to implement IConfigureNamedOptions try something like this:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options =>
{
options.Cookie.Name = "TestName";
}
Related
Is it possible to resolve an instance of ISettingsService from the ConfigureServices method in Startup(.cs) - webapplication?
I've implemented a SettingsService which is able to retrieve the database connectionstring from an external source (secure credentials store). Within the ConfigureServices I need an instance of the ISettingsService in order to get the connectionstring and pass it to the services.AddSqlServer<MyDbContext>(connectionstring) method.
While creating the instance (using var provider = services.BuildServiceProvider(); var settings = provider.GetService<ISettingsProvider>();) Visual Studio displays the next error:
Another developer posted a similar question on StackOverflow and the answer provides a solution in case of AddSingleton/ AddTransient. What is the correct way to apply it on the AddSqlServer call? Or could you provide another solution to avoid the warning/ error message?
The Intellisense comment for .AddSqlServer actually says to use .AddDbContext if you need more control, and that's certainly the correct option.
If you refer to the source code here, you can see that all .AddSqlServer is actually doing is calling .AddDbContext and configuring the options accordingly. We can therefore write our own solution like this:
services.AddDbContext<DbContext>((serviceProvider, options) => {
var settings = serviceProvider.GetService<ISettingsProvider>();
// I don't know what methods your ISettingsProvider makes available
// so adjust accordingly
string connectionString = settings.GetSetting("connectionString");
options.UseSqlServer(connectionString);
});
Of course you can make other changes to the options here, and .UseSqlServer can also take a Action<SqlServerDbContextOptionsBuilder> (options.UseSqlServer(connectionString, opts => opts.EnableRetryOnFailure()), etc.) to further configure it.
I'm working with Identity for the first time. I'm following along with Microsoft's Policy-based authorization tutorial, but when I add a policy and requirement, the handler for that requirement is never called. In fact, it acts like the handler is never retrieved from DI (if I comment out the line adding the handler to the DI container, the app's execution doesn't change at all).
The NotLoggedInHandler is meant to ensure that certain pages are only accessed by users who aren't logged in. The handler just succeeds and returns, so the requirement should always pass:
public class NotLoggedInHandler : AuthorizationHandler<NotLoggedInRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, NotLoggedInRequirement requirement)
{
context.Succeed(requirement);
return Task.CompletedTask;
}
}
But when I access a protected Razor Page, I get this in my log output:
[xx:xx:xx INF] Authorization failed. These requirements were not met: WebApp.Policies.NotLoggedInRequirement
I've fiddled with the order of adding services. It doesn't seem to matter whether NotLoggedInHandler is registered before or after services.AddAuthorization.
My Startup.cs file looks like this:
public class Startup
{
// Other methods/ctor omitted
public void ConfigureServices(IServiceCollection services)
{
// Identity services omitted
// Set up Authentication
services.AddAuthentication(...);
// Set up Authorization
services.AddAuthorization(
options =>
{
options.AddPolicy(
"RequireAnonymous",
policy =>
{
policy.Requirements.Add(new NotLoggedInRequirement());
}
);
}
);
services.AddTransient<AuthorizationHandler<NotLoggedInRequirement>, NotLoggedInHandler>();
// Other services omitted, not related to Identity/auth
}
}
Turns out, I was making assumptions and just needed a step back. As detailed in the tutorial from Microsoft, handlers are registered against the IAuthorizationHandler interface.
The tutorial shows how to create a handler for a single requirement and a handler for multiple requirements, but only explicitly shows how to register a handler for multiple requirements. It wasn't explicitly stated in the tutorial that the process is identical, and based on my experience with ASP.NET's DI container, I thought my solution made sense (because a one-to-one handler implements IAuthorizationHandler<TRequirement>, but a one-to-many handler implements IAuthorizationHandler).
However, it is the same regardless. I'm not sure how ASP.NET resolves these dependencies since any number of handlers will be registered to the IAuthorizationHandler interface, but it works regardless.
Changing this:
services.AddTransient<AuthorizationHandler<NotLoggedInRequirement>, NotLoggedInHandler>();
to this:
services.AddTransient<IAuthorizationHandler, NotLoggedInHandler>();
effectively solved the problem.
I've started to implement health checks in my .NET Core Web API. There are two health checks, one for checking if the SQL Server has any pending migrations and the other is checking if another API is live. Both added within ConfigureServices in Startup class.
In order to do the migration check, I need to access the DbContext which has already been added to DI using AddDbContext and to check the API, I need to get the API base url from configuration which is already in DI using services.Configure<>. I use the following code to get access to the DbContext.
I'm using AspNetCore.HealthChecks.Uris package to use AddUrlGroup health check.
var sp = services.BuildServiceProvider();
var dbContext = sp.GetService<AppDbContext>();
var apis = sp.GetService<IOptions<InternalServicesConfiguration>>().Value;
services.AddHealthChecks().AddCheck("Database", new SqlDatabaseHealthCheck(dbContext), tags: new[] { "ready" })
.AddUrlGroup(new Uri(new Uri(apis.Api1BaseUri), "/health/live"), HttpMethod.Get, "API 1", HealthStatus.UnHealthy, new []{"ready"});
But services.BuildServiceProvider() shows the following warning:
Calling 'BuildServiceProvider' from application code results in an additional copy of singleton services being created. Consider alternatives such as dependency injecting services as parameters to 'Configure'
I can get the api base urls using
_configuration.GetSection("InternalServicesConfiguration").Get(typeof(InternalServicesConfiguration));
But I can't think of an alternative way to access the DbContext.
Any help much appreciated.
You can register your healthcheck like this:
services.AddHealthChecks()
.AddCheck<ExampleHealthCheck>("Database");
And then just inject your DbContext into ExampleHealthCheck class, which has to implement IHealthCheck interface
There are some healthchecks you can use directly for EF in the official docs
But if you want to write any custom or more complex checks, your best bet might be to create a class that implements the IHealthCheck interface, where you can inject anything you want.
Also from the docs about Custom health checks, an example:
public class ExampleHealthCheck : IHealthCheck
{
public Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context,
CancellationToken cancellationToken = default(CancellationToken))
{
var healthCheckResultHealthy = true;
if (healthCheckResultHealthy)
{
return Task.FromResult(
HealthCheckResult.Healthy("A healthy result."));
}
return Task.FromResult(
HealthCheckResult.Unhealthy("An unhealthy result."));
}
}
which, as kebek alerady answered, you will register like
services.AddHealthChecks()
.AddCheck<ExampleHealthCheck>("example_health_check");
With regard to accessing IOptions (please see updated health check). Is there another way other than getting it using _configuration.GetSection("").Get<>()
You could register those options in a following way (in ConfigureServices):
services.Configure<InternalServicesConfiguration>(Configuration.GetSection("InternalServicesConfiguration"));
And to get those options, in your class just inject IOptions<InternalServicesConfiguration> options, where the options.Value prop is the configuration value
I need to access a service inside ConfigureServices method in Startup.cs and I do this:
services.AddScoped<ICustomService, CustomService>();
var sp = services.BuildServiceProvider();
var service = sp.GetService<ICustomService>(); // this is null
However var service above is always null.
What do i do wrong?
I had this sort of problem - I had a singleton 'settings' service which I wanted to use. I solved it by Actually creating one then registering that exact instance with DI via the overload that lets you specify a 'provider', rather than just registering the class, and adding a nice big comment explaining this:
var settingsService = new SettingsService(_hostingEnvironment);
//Add a concrete settings service which is then registered as the de facto settings service for all time.
//we need to do this as we want to use the settings in this method, and there isn't a satisfactory method to
//pull it back out of the IServiceCollection here (we could build a provider, but then that's not the same provider
//as would be build later... at least this way I have the exact class I'll be using.
services.AddSingleton<ISettingsService, SettingsService>((p) => settingsService);
..
..
..
var thing = settingsService.SomeSettingIWant();
If what you want isn't a singleton but is something transient, then I guess you can just create a concrete class for it right there? I know it probably feels a bit like cheating, but it would work fine...
I'm trying to configure my services for an ASP.NET Core 2.0 app/website.
I wish to reference some key/values from my appsettings.json file, in this method.
I'm not sure if what I'm going is OK or not:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvcCore()
.AddJsonFormatters()
.AddCors();
var applicationSettings = Configuration.GetSection("Settings").Get<ApplicationSettings>();
services.AddSingleton(applicationSettings);
// ** THIS IS WHAT I ORIGINALLY HAD, BUT IT'S ONLY SETTING
// THE VALUE IN DI/IOC.
//services.Configure<ApplicationSettings>(options => Configuration.GetSection("Settings")
// .Bind(options));
var foo = new Foo(applicationSettings.SomeSetting);
services.AddSingleton(foo);
}
See how i'm manually adding a singleton and then later, referring a value from the app settings instance?
vs
just configuring ...
So, is either way OK or is there a specific reason for either/or?
Remember -> i'm going to need to inject my settings into controllers, etc...
Technically, you can do either. In both cases, you have the configuration registered and available through dependency injection, so everything can depend on it and will get the configuration instance.
You are also using the centrally set up Configuration there, so you have all the benefits from the configuration stack there, e.g. multiple providers or environment specific overrides.
However, the favor has definitely moved to the IOptions way of consuming custom configuration. It’s the “state of the art” and used throughout ASP.NET Core for literally everything. It also allows you to switch to options that can be updated at runtime. That’s very powerful and might become useful eventually (not necessarily for your specific situation with the singleton, but maybe for something else).
It’s also really easy to set this up, actually shorter than what you tried:
services.Configure<ApplicationSettings>(Configuration.GetSection("Settings"));
services.AddSingleton<Foo>();
Note that, even for singletons, you shouldn’t explicitly create a new instance of it, but let DI handle that. If your class has the correct constructor, dependencies will be automatically injected anyway:
public class Foo
{
private readonly ApplicationSettings _settings;
public Foo (IOptions<ApplicationSettings> settings)
{
_settings = settings.Value;
}
}
Of course, Foo can also have more dependencies here. Since it’s going to be constructed by DI, you can just add more dependencies in the constructor, without having to update some new call somewhere.
If you need to configure certain services with settings that depend on your configuration, you still should not bind your configuration there directly. All of configuration is DI-based, so you just need to inject the right thing; a IConfigureOptions<T>. That’s basically the thing that provides the IOptions<T> to services later. In your JWT case, this could look like this:
// instead of passing an option configuration delegate here…
services.AddAuthentication().AddJwtBearer();
// … we register a IConfigureOptions<JwtBearerOptions> instead
services.AddSingleton<IConfigureOptions<JwtBearerOptions>, ConfigureJwtBearerOptions>();
// … ConfigureJwtBearerOptions could look like this:
class ConfigureJwtBearerOptions : IConfigureOptions<JwtBearerOptions>
{
private readonly ApplicationSettings _settings;
public ConfigureJwtBearerOptions(IOptions<ApplicationSettings> settings)
{
_settings = settings.Value;
}
public void Configure(JwtBearerOptions options)
{
// configure JwtBearerOptions here, and use your ApplicationSettings
options.MetadataAddress = _settings.JwtMetadataAddress;
}
}
This might seem unnecessarily verbose compared to just passing a delegate to AddJwtBearer() but note that this is exactly what happens under the hood when you pass that delegate: An IConfigureOptions<JwtBearerOptions> object will be created that calls your delegate in the Configure() call. So this is really just the same.
Note that for authentication schemes, you might actually set up a IConfigureNamedOptions<T> instead, which is almost the same thing except it can configure the options based on a name. For authentication schemes, that is the scheme name, so basically you check the scheme name in Configure() and then decide how to configure your options.
As for creating singleton instances, especially expensive ones, I would argue that ConfigureServices is the wrong place for such a thing. ConfigureServices is called very early in the application startup phase, when the whole DI infrastructure does not exist yet. So you could not rely on anything when creating your instance. I would also argue that it is still not your job to create the object but you should DI handle the creation of it and as such give it also control over its lifecycle.
If you absolutely need to control when the instance is created, I would suggest you to use the lifecycle events for this: Basically, after the application has set up properly but before a first request comes in, you request the instance of your services and initialize it. That way, you can still have it fully depend on DI, and it won’t be created lazily with the first request.
You can register lifecycle handlers in the Configure method:
public void Configure(IApplicationBuilder app, IApplicationLifetime applicationLifetime)
{
applicationLifetime.ApplicationStarted.Register(() =>
{
// application has started, request the singleton here to trigger DI to
// create the instance
app.ApplicationServices.GetService<ExpensiveSingleton>();
});
// …
}
}
Well the problem with that approach is that it will be impossible to load multiple configuration sections through DI. The Configuration API has many features, such as pluggable configuration provides, snapshots, etc.
I would suggest you at least use a class to bind you configuration section against, so DI can inject it based on its type. If you further down the line have need to another configuration class you won't run into issues.
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/configuration