Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using multiple authentication schemes in ASP.NET Core 3.1?

I have been making a web application using ASP.NET Core 3.1 using clean architecture.

I have some class libraries like Infrastructure, Persistence, Domain, Application, and a MVC application project named "Web" as the startup point of my application.

In the Web layer I have "Areas" in which I have an Admin area containing some controllers and action methods which return JSON as my API endpoints to be used in a React-based app.

I also have some controllers in the Web MVC project in Controllers folder which their action methods return html views.

I also use Identity and JWT for my API endpoints but:

- What if I want to use claims-based Identity in my MVC controllers which their action results return html views?

- What is the best practice for using claims-based Identity in ASP.NET Core 3.1 in such an application?

Any help would be appreciated.

like image 245
Aspian Avatar asked Jun 11 '20 10:06

Aspian


People also ask

How many types of authentication are there in asp net core?

Authentication : It is the process of ensuring the user's identity and authenticity. ASP.NET allows four types of authentications: Windows Authentication.

Can you have multiple JWT tokens?

You can use multiple JWT tokens, but Tableau doesn't offer a way to limit the number of concurrent 'connected app' users.

What is authentication scheme in asp 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.


2 Answers

After doing some research, I found the solution in ASP.NET core Authorization documentation in an article with the title "Authorize with a specific scheme in ASP.NET Core".

Based on the mentioned article in Microsoft ASP .NET core documentation, In some scenarios, such as Single Page Applications (SPAs), it's common to use multiple authentication methods. For example, the app may use cookie-based authentication to log in and JWT bearer authentication for JavaScript requests.

An authentication scheme is named when the authentication service is configured during authentication. For example:

public void ConfigureServices(IServiceCollection services)
{
    // Code omitted for brevity

    services.AddAuthentication()
        .AddCookie(options => {
            options.LoginPath = "/Account/Unauthorized/";
            options.AccessDeniedPath = "/Account/Forbidden/";
        })
        .AddJwtBearer(options => {
            options.Audience = "http://localhost:5001/";
            options.Authority = "http://localhost:5000/";
        });

In the preceding code, two authentication handlers have been added: one for cookies and one for bearer.

Selecting the scheme with the Authorize attribute

[Authorize(AuthenticationSchemes = 
    JwtBearerDefaults.AuthenticationScheme)]
public class MixedController : Controller

In the preceding code, only the handler with the "Bearer" scheme runs. Any cookie-based identities are ignored.

This is the solution which solved my problem and I thought it would be good to share it with you guys for those who need this.

like image 189
Aspian Avatar answered Oct 11 '22 08:10

Aspian


Multiple Authentication Schemes in .Net Core 3.1 or .Net 5.0

Startup.cs

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
                    .AddCookie(x =>
                    {
                        x.LoginPath = "/";
                        x.ExpireTimeSpan = TimeSpan.FromMinutes(Configuration.GetValue<int>("CookieExpiry"));
                    })
                    .AddJwtBearer(x =>
                    {
                        x.RequireHttpsMetadata = false;
                        x.SaveToken = true;
                        x.TokenValidationParameters = new TokenValidationParameters
                        {
                            ValidateIssuerSigningKey = true,
                            IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Configuration.GetValue<string>("JWTSecret"))),
                            ValidateIssuer = false,
                            ValidateAudience = false
                        };
                    });

            services.AddAuthorization(options =>
            {
                var defaultAuthorizationPolicyBuilder = new AuthorizationPolicyBuilder(CookieAuthenticationDefaults.AuthenticationScheme, JwtBearerDefaults.AuthenticationScheme);
                defaultAuthorizationPolicyBuilder = defaultAuthorizationPolicyBuilder.RequireAuthenticatedUser();
                options.DefaultPolicy = defaultAuthorizationPolicyBuilder.Build();
            });

/api/auth/login

public async Task<AuthenticationResult> Login([FromForm] string userName, [FromForm] string password, [FromHeader] string authmode = "")
{
    if (userName != "demo" || password != "demo")
        return new AuthenticationResult { HasError = true, Message = "Either the user name or password is incorrect." };

    var claims = new Claim[]
    {
        new Claim(ClaimTypes.Name, userName)
    };
    

    if(authmode?.ToLower() == "token")
    {
        var tokenHandler = new JwtSecurityTokenHandler();
        var key = Encoding.ASCII.GetBytes(_config.GetValue<string>("JWTSecret"));
        var tokenDescriptor = new SecurityTokenDescriptor
        {
            Subject = new ClaimsIdentity(claims, "JWT"),
            Expires = DateTime.UtcNow.AddMinutes(_config.GetValue<int>("JWTExpiry")),
            SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
        };
        var token = tokenHandler.CreateToken(tokenDescriptor);
        var jwt = tokenHandler.WriteToken(token);
        return new AuthenticationResult { Token = jwt };
    }
    else
    {
        ClaimsPrincipal princ = new ClaimsPrincipal(new ClaimsIdentity(claims, "COOKIE"));
        await HttpContext.SignInAsync(princ);
        return new AuthenticationResult();
    }
}

Output:

enter image description here enter image description here

enter image description here enter image description here

like image 38
Palanikumar Avatar answered Oct 11 '22 07:10

Palanikumar