I\'ve created a new ASP.NET Core Web Application project in VS17 using the \"Web Application (Model-View-Controller)\" template and \".Net Framework\" + \"ASP.NET Core 2\" as th
If I understand the question correctly then I believe that there is a solution. In the following example I am using cookie AND bearer authentication in a single app. The [Authorize]
attribute can be used without specifying the scheme, and the app will react dynamically, depending on the method of authorization being used.
services.AddAuthentication
is called twice to register the 2 authentication schemes. The key to the solution is the call to services.AddAuthorization
at the end of the code snippet, which tells ASP.NET to use BOTH schemes.
I've tested this and it seems to work well.
(Based on Microsoft docs.)
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = "oidc";
})
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.Authority = "https://localhost:4991";
options.RequireHttpsMetadata = false;
options.ClientId = "WebApp";
options.ClientSecret = "secret";
options.ResponseType = "code id_token";
options.Scope.Add("api");
options.SaveTokens = true;
});
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Authority = "https://localhost:4991";
options.RequireHttpsMetadata = false;
// name of the API resource
options.Audience = "api";
});
services.AddAuthorization(options =>
{
var defaultAuthorizationPolicyBuilder = new AuthorizationPolicyBuilder(
CookieAuthenticationDefaults.AuthenticationScheme,
JwtBearerDefaults.AuthenticationScheme);
defaultAuthorizationPolicyBuilder =
defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser();
options.DefaultPolicy = defaultAuthorizationPolicyBuilder.Build();
});
EDIT
This works for authenticated users, but simply returns a 401 (unauthorized) if a user has not yet logged in.
To ensure that unauthorized users are redirected to the login page, add the following code to the Configure
method in your Startup class. Note: it's essential that the new middleware is placed after the call the app.UseAuthentication()
.
app.UseAuthentication();
app.Use(async (context, next) =>
{
await next();
var bearerAuth = context.Request.Headers["Authorization"]
.FirstOrDefault()?.StartsWith("Bearer ") ?? false;
if (context.Response.StatusCode == 401
&& !context.User.Identity.IsAuthenticated
&& !bearerAuth)
{
await context.ChallengeAsync("oidc");
}
});
If you know a cleaner way to achieve this redirect, please post a comment!