Search code examples
c#authorizationjwtasp.net-core-webapinetcoreapp2.1

The AuthorizeAttribute doesn't effect authorization using JWT in dotnet core webapi 2.1 application


I'm trying to use JWT in a core webapi application. Here is my Startup.ConfigureServices():

services.AddDbContextPool("Bla Bla");
services.AddIdentity<IdentityUser, IdentityRole>("Bla Bla");

JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddAuthentication(o => {
    o.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    o.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
    o.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(c => {
    c.RequireHttpsMetadata = false;
    c.SaveToken = true;
    c.TokenValidationParameters = 
        new TokenValidationParameters {
            ValidIssuer = Configuration["JwtIssuer"],
            ValidAudience = Configuration["JwtIssuer"],
            IssuerSigningKey = new SymmetricSecurityKey(
                        Encoding.UTF8.GetBytes(Configuration["JwtKey"])),
            ClockSkew = TimeSpan.Zero
        };
});

services.AddRouting("Bla Bla");
services.AddMvcCore("Bla Bla").AddControllersAsServices();

And this is Startup.Configure() method:

app.UseAuthentication();
app.UseMvc(rb => 
    { rb.MapRoute("api_default", "{controller}/{action}/{id?}"); });

Anyway, I have created a protect action to test (which I'm expecting to return an HTTP 401 Unauthorized error):

public class AccountController : ControllerBase {
    [HttpGet]
    [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
    public async Task<object> Info() {
        return "Authorized!";
    }
}

But its getting authorized and responsing "Authorized!" all the time. It seems the Authorize attribute doesn't effect at all. Am I missing something?

P.S. I have tried both [Authorize] and [Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)] attribute.

P.S.2 I have tried extending the controller from both ControllerBase and Controller.

P.S.3 I have tried without clearing default claims (removed this line JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();).

None of them worked.

Framework and packages info:

  • Target Framework: netcoreapp2.1
  • Microsoft.AspNetCore Version = 2.1.6
  • Microsoft.AspNetCore.Authentication.JwtBearer Version = 2.1.2
  • Microsoft.AspNetCore.Identity.EntityFrameworkCore Version = 2.1.6
  • Microsoft.AspNetCore.Mvc.Core Version = 2.1.3

UPDATE:

According to @sellotape's comment, I have returned the User object from the action:

[HttpGet]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public async Task<object> Info() {
    return User;
}

And here is the output JSON:

{
    "identities": [
        {
            "isAuthenticated": false,
            "claims": [],
            "roleClaimType": "http://schemas.microsoft.com/ws/2008/06/identity/claims/role",
            "nameClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
        }
    ],
    "identity": {
        "isAuthenticated": false,
        "claims": [],
        "roleClaimType": "http://schemas.microsoft.com/ws/2008/06/identity/claims/role",
        "nameClaimType": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"
    },
    "claims": []
}

Solution

  • The main issue is that when you use .AddMvcCore(), you're only wiring up a small part of what you get when you use .AddMvc() instead. For many solutions, it's simpler to just use the latter, as you then automatically get the following added and ready to use [source]:

    • API Explorer
    • Authorization
    • Views
    • Razor View Engine
    • Razor Pages
    • JSON Formatters
    • CORS
    • (a few others)

    If you prefer to only add what you absolutely need, you can elect to use .AddMvcCore() instead, but then you need to explicitly add the MVC services you require; e.g. in this case (Authorization), you would need to

    services.AddMvcCore()
            .AddAuthorization();
    

    Note how .AddAuthorization() here is being applied to the result of services.AddMvcCore(), which is an IMvcBuilder, not to services, which is an IServiceCollection.