In dotnet core 1.1 asp, I was able to configure and use identity middleware followed by jwt middleware by doing the following:
app.UseIdentity();
app.UseJwtBearerAuthentication(new JwtBearerOptions() {});
This has now changed in that we implement the middleware with:
app.UseAuthentication();
Configuration of the settings is done via the ConfigureServices section of Startup.cs.
There are some references to the use of authorization schema's in the migration documentation:
https://docs.microsoft.com/en-us/aspnet/core/migration/1x-to-2x/identity-2x#authentication-middleware-and-services
In 2.0 projects, authentication is configured via services. Each
authentication scheme is registered in the ConfigureServices method of
Startup.cs. The UseIdentity method is replaced with UseAuthentication.
Additionally there is a reference to:
Setting Default Authentication Schemes
In 1.x, the AutomaticAuthenticate and AutomaticChallenge properties
were intended to be set on a single authentication scheme. There was
no good way to enforce this.
In 2.0, these two properties have been
removed as flags on the individual AuthenticationOptions instance and
have moved into the base AuthenticationOptions class. The properties
can be configured in the AddAuthentication method call within the
ConfigureServices method of Startup.cs:
Alternatively, use an overloaded version of the AddAuthentication
method to set more than one property. In the following overloaded
method example, the default scheme is set to
CookieAuthenticationDefaults.AuthenticationScheme. The authentication
scheme may alternatively be specified within your individual
[Authorize] attributes or authorization policies.
Is it still possible in dotnet core 2.0 to use multiple authentication schemas? I cannot get the policy to respect the JWT configuration ("Bearer" schema), and only Identity is working at present with both configured. I can't find any samples of multiple authentication schemas.
Edit:
I've reread the documentation, and now understand that the:
app.UseAuthentication()
adds automatic authentication against a default schema. Identity configures the default schemas for you.
I have gotten around the issue with what seems like a hack working against the new api's by doing the following in Startup.cs Configure:
app.UseAuthentication();
app.Use(async (context, next) =>
{
if (!context.User.Identity.IsAuthenticated)
{
var result = await context.AuthenticateAsync(JwtBearerDefaults.AuthenticationScheme);
if (result?.Principal != null)
{
context.User = result.Principal;
}
}
await next.Invoke();
});
Is this the correct way to do this, or should I be utilising the framework, DI and interfaces for custom implementations of IAuthenticationSchemeProvider?
Edit - Futher details of the implementation and where to find it.
The JWT Config can be found here, and I am using policies to define the authorization, which include the accepted auth schema's:
https://github.com/Arragro/ArragroCMS/blob/master/src/ArragroCMS.Management/Startup.cs
Custom middleware is still implemented. The Auth controller is here:
https://github.com/Arragro/ArragroCMS/blob/master/src/ArragroCMS.Web.Management/ApiControllers/AuthController.cs
It uses API Keys generated by the app to get read only access to data. You can find the implementation of a controller utilising the policy here:
https://github.com/Arragro/ArragroCMS/blob/master/src/ArragroCMS.Web.Management/ApiControllers/SitemapController.cs
Change the DB Connection string to point to your SQL Server, and run the application. It migrates the DB automatically and configures an admin user ([email protected] - ArragroPassword1!). Then go to the Settings tab in the menu bar and click "Configure the JWT ReadOnly API Key Settings" to get a key. In postman, get a jwt token by configuring a new tab and setting it to POST with the following address:
http://localhost:5000/api/auth/readonly-token
Supply the headers: Content-Type: application/json
Supply the body:
{
"apiKey": "the api token from the previous step"
}
Copy the token in the response, and then use the following in postman:
http://localhost:5000/api/sitemap/flat
Authorization: "bearer - The token you received in the previous request"
It will work inititally because of the custom middleware. Comment out the code mentioned above and try again and you will receive a 401.
Edit -@DonnyTian's answer below covers my solution in his comments. The problem I was having was setting a default policy on UseMvc, but not supplying the schema's:
services.AddMvc(config =>
{
var defaultPolicy = new AuthorizationPolicyBuilder(new[] { JwtBearerDefaults.AuthenticationScheme, IdentityConstants.ApplicationScheme })
.RequireAuthenticatedUser()
.Build();
config.Filters.Add(new AuthorizeFilter(defaultPolicy));
config.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
config.Filters.Add(new ValidateModelAttribute());
});
Following the advice, this works without custom middleware.
See Question&Answers more detail:
os