Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I setup multiple auth schemes in ASP.NET Core 2.0?

I'm trying to migrate my auth stuff to Core 2.0 and having an issue using my own authentication scheme. My service setup in startup looks like this:

var authenticationBuilder = services.AddAuthentication(options => {     options.AddScheme("myauth", builder =>     {         builder.HandlerType = typeof(CookieAuthenticationHandler);     }); })     .AddCookie(); 

My login code in the controller looks like this:

var claims = new List<Claim> {     new Claim(ClaimTypes.Name, user.Name) };  var props = new AuthenticationProperties {     IsPersistent = persistCookie,     ExpiresUtc = DateTime.UtcNow.AddYears(1) };  var id = new ClaimsIdentity(claims); await HttpContext.SignInAsync("myauth", new ClaimsPrincipal(id), props); 

But when I'm in a controller or action filter, I only have one identity, and it's not an authenticated one:

var identity = context.HttpContext.User.Identities.SingleOrDefault(x => x.AuthenticationType == "myauth"); 

Navigating these changes has been difficult, but I'm guessing that I'm doing .AddScheme wrong. Any suggestions?

EDIT: Here's (essentially) a clean app that results not in two sets of Identities on User.Identies:

namespace WebApplication1.Controllers {     public class Testy : Controller     {         public IActionResult Index()         {             var i = HttpContext.User.Identities;             return Content("index");         }          public async Task<IActionResult> In1()         {             var claims = new List<Claim> { new Claim(ClaimTypes.Name, "In1 name") };             var props = new AuthenticationProperties  { IsPersistent = true, ExpiresUtc = DateTime.UtcNow.AddYears(1) };             var id = new ClaimsIdentity(claims);             await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, new ClaimsPrincipal(id), props);             return Content("In1");         }          public async Task<IActionResult> In2()         {             var claims = new List<Claim> { new Claim(ClaimTypes.Name, "a2 name") };             var props = new AuthenticationProperties { IsPersistent = true, ExpiresUtc = DateTime.UtcNow.AddYears(1) };             var id = new ClaimsIdentity(claims);             await HttpContext.SignInAsync("a2", new ClaimsPrincipal(id), props);             return Content("In2");         }          public async Task<IActionResult> Out1()         {             await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);             return Content("Out1");         }          public async Task<IActionResult> Out2()         {             await HttpContext.SignOutAsync("a2");             return Content("Out2");         }     } } 

And Startup:

namespace WebApplication1 {     public class Startup     {         public Startup(IConfiguration configuration)         {             Configuration = configuration;         }          public IConfiguration Configuration { get; }          public void ConfigureServices(IServiceCollection services)         {             services.AddAuthentication(options =>             {                 options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;                 })                 .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)                 .AddCookie("a2");              services.AddMvc();         }          public void Configure(IApplicationBuilder app, IHostingEnvironment env)         {             app.UseAuthentication();              app.UseMvc(routes =>             {                 routes.MapRoute(name: "default", template: "{controller=Home}/{action=Index}/{id?}");             });         }     } } 
like image 961
Jeff Putz Avatar asked Aug 15 '17 14:08

Jeff Putz


People also ask

How many types of authentication are there in ASP.NET Core?

This blog starts with authentication and authorization concepts and after that explains the three default important ways and three custom authentication ways for doing authentication and authorization i.e. windows, forms ,passport, multipass, JWT and SAML authentication.

What is authentication scheme .NET core?

Authentication is the process of determining a user's identity. Authorization is the process of determining whether a user has access to a resource. In ASP.NET Core, authentication is handled by the authentication service, IAuthenticationService, which is used by authentication middleware.

What are different authentication schemes?

The 4 main schemes of REST API authentication are- Basic Authentication. Token Based Authentication. API Key Based Authentication. OAuth (Open Authorization)

What is the default type of authentication for ASP.NET Core MVC?

The windows Authentication provider lets you authenticates users based on their windows accounts. This provider uses IIS to perform the authentication and then passes the authenticated identity to your code. This is the default provided for ASP.net.


1 Answers

Edit of December 2019: please consider this answer before anything else: Use multiple JWT Bearer Authentication

My old answer (that does not fit using multiple JWT but only JWT + API key, as a user commented):

Another possibility is to determine at runtime which authentication policy scheme to choose, I had the case where I could have an http authentication bearer token header or a cookie.

So, thanks to https://github.com/aspnet/Security/issues/1469

JWT token if any in request header, then OpenIdConnect (Azure AD) or anything else.

public void ConfigureServices(IServiceCollection services)     {         // Add CORS         services.AddCors();          // Add authentication before adding MVC         // Add JWT and Azure AD (that uses OpenIdConnect) and cookies.         // Use a smart policy scheme to choose the correct authentication scheme at runtime         services             .AddAuthentication(sharedOptions =>             {                 sharedOptions.DefaultScheme = "smart";                 sharedOptions.DefaultChallengeScheme = "smart";             })             .AddPolicyScheme("smart", "Authorization Bearer or OIDC", options =>             {                 options.ForwardDefaultSelector = context =>                 {                     var authHeader = context.Request.Headers["Authorization"].FirstOrDefault();                     if (authHeader?.StartsWith("Bearer ") == true)                     {                         return JwtBearerDefaults.AuthenticationScheme;                     }                     return OpenIdConnectDefaults.AuthenticationScheme;                 };             })             .AddJwtBearer(o =>             {                 o.Authority = Configuration["JWT:Authentication:Authority"];                 o.Audience = Configuration["JWT:Authentication:ClientId"];                 o.SaveToken = true;             })             .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme)             .AddAzureAd(options => Configuration.Bind("AzureAd", options));          services             .AddMvc(config =>             {                 var policy = new AuthorizationPolicyBuilder()                                  .RequireAuthenticatedUser()                                  .Build();                 // Authentication is required by default                 config.Filters.Add(new AuthorizeFilter(policy));                 config.RespectBrowserAcceptHeader = true;             });                          ...                          } 

Edit of 07/2019: I must add a link to the following proposal, because it's very helpful too: you may not use parameters in AddAuthentication() as I did, because this would setup a default scheme. Everything is well explained here: Use multiple JWT Bearer Authentication. I really like this other approach!

like image 65
barbara.post Avatar answered Sep 23 '22 01:09

barbara.post