Search code examples
c#asp.netauthenticationasp.net-mvc-5jwt

Asp.Net multiple AuthenticationSchemas - User doesn't get redirected to LoginPath Uri


I'm trying to set up an ASP.Net 5 web project with JWTBearer authentication for API Controllers (Controllers decorated with the APIController attribute) and CookieAuthentication for MVC Controllers (Controller classes derived from Controller, to render Views). The relevant part of my ConfigureServices method in the Startup Class looks like this:

services
    .AddAuthentication(options =>
    {
        options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    })
    .AddJwtBearer(options =>
    {
        options.SaveToken = true;
        options.TokenValidationParameters = new TokenValidationParameters
        {
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes("My Secret Key")),
            ValidateAudience = false,
            ValidateIssuer = false,
            RequireExpirationTime = false,
            ValidateLifetime = true
        };
    })
    .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
    {
        options.LoginPath = "/account/login";
        options.LogoutPath = "/account/logout";
        options.AccessDeniedPath = "/account/accessdenied";
        options.Cookie = new CookieBuilder {SameSite = SameSiteMode.Strict};
        options.ExpireTimeSpan = TimeSpan.FromMinutes(20);
    });

var schemePolicy = new AuthorizationPolicyBuilder(
        CookieAuthenticationDefaults.AuthenticationScheme,
        JwtBearerDefaults.AuthenticationScheme)
    .RequireAuthenticatedUser()
    .Build();

services.AddAuthorization(o => o.DefaultPolicy = schemePolicy);

In an MCV Controller I have an Action like the below:

[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
public IActionResult AnActionForAuthenticatedUsers()
{
    //  do some stuff...
    return View();
}

Now I would expect that when an unauthenticated request for this action comes in the request will be forwarded to /account/login but it is not. Instead a 401 statuscode is returned.

The webserver says:

info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
      Authorization failed. These requirements were not met:
      DenyAnonymousAuthorizationRequirement: Requires an authenticated user.
info: Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler[12]
      AuthenticationScheme: Cookies was challenged.
info: Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerHandler[12]
      AuthenticationScheme: Bearer was challenged.

What am I missing here?


Solution

  • The problem here is not in Authentication policy, but in Authorization configuration Create a separate policy for each type of Authorization and that would work as you are expecting:

    services.AddAuthorization(o =>
    {
        o.AddPolicy(CookieAuthenticationDefaults.AuthenticationScheme, schemePolicy);
        o.AddPolicy(JwtBearerDefaults.AuthenticationScheme, schemePolicy);
    });