简体   繁体   中英

ASP.NET Core Two Authentication Schemes (JWT + CookieAuth)

I have an MVC web app and an exposed API that I want to use cookieauth for the web app and JWT for the exposed API. I am testing the API and it always seems to default to the cookie auth handler in the middleware for some reason.

Below in the startup, I added two event handlers just to test breakpoints and the API hits the cookie event handler instead of the JWT handler. I specify the scheme in the action so not really sure why it's not working.

Startup.cs Configure Services

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        })
        .AddCookie(options =>
        {
            options.ExpireTimeSpan = TimeSpan.FromMinutes(20);
            options.SlidingExpiration = true;
            options.AccessDeniedPath = "/Error/Index";
            options.LoginPath = "/Login/Login";
            options.Cookie.Name = "CookieAuthentication";
            options.Cookie.HttpOnly = true;
            options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
            options.Events.OnRedirectToLogin = e =>
            {
                return Task.CompletedTask;
            };
        })
        .AddJwtBearer(options =>
        { 
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = Environment.GetEnvironmentVariable("JwtIssuer") ?? Configuration["Jwt:Issuer"],
                ValidAudience = Environment.GetEnvironmentVariable("JwtIssuer") ?? Configuration["Jwt:Issuer"],
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Environment.GetEnvironmentVariable("JwtKey") ?? Configuration["Jwt:Key"])),
            };
            options.Events.OnChallenge = e =>
            {
                return Task.CompletedTask;
            };
        });
    }
}

StartUp Configure

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseAuthentication();
    app.UseAuthorization();
}

As an example, I do this with my API and doesn't hit the correct scheme in the startup

[HttpGet]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public IActionResult Foo()
{
    return Ok();
}

you have to register 2 auth scheme like that:

    //Cookie
    _ = services.AddAuthentication(options =>
    {
        options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    }).AddCookie(options =>
    {
        options.ExpireTimeSpan = TimeSpan.FromMinutes(20);
        options.SlidingExpiration = true;
        options.AccessDeniedPath = "/Error/Index";
        options.LoginPath = "/Login/Login";
        options.Cookie.Name = "CookieAuthentication";
        options.Cookie.HttpOnly = true;
        options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
        options.Events.OnRedirectToLogin = e =>
        {
            return Task.CompletedTask;
        };
    });

    //Jwt
    _ = services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddJwtBearer(options =>
        {
            options.TokenValidationParameters = new TokenValidationParameters
            {
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ValidateIssuerSigningKey = true,
                ValidIssuer = Environment.GetEnvironmentVariable("JwtIssuer") ?? Configuration["Jwt:Issuer"],
                ValidAudience = Environment.GetEnvironmentVariable("JwtIssuer") ?? Configuration["Jwt:Issuer"],
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Environment.GetEnvironmentVariable("JwtKey") ?? Configuration["Jwt:Key"])),
            };
            options.Events.OnChallenge = e =>
            {
                return Task.CompletedTask;
            };
        });

And decorate your actions with the auth scheme you need:

[HttpGet]
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public IActionResult Foo()
{
    return Ok();
}

[HttpGet]
[Authorize(AuthenticationSchemes = CookieAuthenticationDefaults.AuthenticationScheme)]
public IActionResult FooCookie()
{
    return Ok();
}

EDIT: Use a base controller to make authentication inheritance (attribute can be inherited):

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
public class MyJwtBaseController : ApiController
{

}

If you want to unauthorize a specific action:

public class MyController : MyJwtBaseController 
{
   public IActionResult Foo()  //Inherits base controller auth
   {
       return Ok();
   }

   [AllowAnonymous]
   public IActionResult FooUnauthorize()  //No auth
   {
       return Ok();
   }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM