JWT with authorization client side

DsLond 21 Reputation points
2021-10-03T10:30:21.377+00:00

Hello,
I have created web api server with jwt auth. In jwt I can get role claims for users. Roles are user, manager and admin.

My client is asp.net core MVC. So I have a layout page with menu items. We can use "@if(User.IsInRole("Admin"))" to hide/show menu items in web app without consuming api.. My question is how can I make menu items show and hide based on user role from jwt consuming api and what is the best practice for this (action or auth filters, middle ware etc.).

Developer technologies ASP.NET ASP.NET Core
{count} votes

Accepted answer
  1. Anonymous
    2021-10-04T08:09:32.333+00:00

    Hi @DsLond ,

    In the MVC application, you can also configure the application using JWT authentication, with the same key, and set the Issuer and Audience. Then, you can create a custom middleware to get user claims from the JWT token, and then add them into the current httpcontext. After that in the MVC view page, you can access the claims from HttpContext.User.

    Please refer the following sample code (in the following sample, I disable verifying Issuer and Audience):

    ConfigureServices method: configure the MVC application use JWT authentication.

        public void ConfigureServices(IServiceCollection services)  
        {  
            ...  
            services.AddAuthentication(option =>  
            {  
                option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;  
                option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;  
    
            }).AddJwtBearer(options =>  
            {  
                options.TokenValidationParameters = new TokenValidationParameters  
                {  
                    ValidateIssuer = false,  
                    ValidateAudience = false,  
                    ValidateLifetime = false,  
                    ValidateIssuerSigningKey = true,  
                    ValidIssuer = Configuration["Jwt:Issuer"],  
                    ValidAudience = Configuration["Jwt:Audience"],  
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"])) //Configuration["JwtToken:SecretKey"]  
                };  
            });  
        }  
    

    In the appsettings.json file, add the same JWT configuration:

      "Jwt": {  
        "Key": "ThisismySecretKey",  
        "Issuer": "Test.com",  
        "Audience": "Test.com"  
      },  
    

    Create a JWTMiddleware middleware with the following code:

    public class JWTMiddleware  
    {  
        private readonly RequestDelegate _next;  
        private readonly IConfiguration _configuration;   
    
        public JWTMiddleware(RequestDelegate next, IConfiguration configuration )  
        {  
            _next = next;  
            _configuration = configuration;   
        }  
    
        public async Task Invoke(HttpContext context)  
        {  
            var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();  
    
            if (token != null)  
                attachAccountToContext(context, token);  
    
            await _next(context);  
        }  
    
        private void attachAccountToContext(HttpContext context, string token)  
        {  
            try  
            {  
                var tokenHandler = new JwtSecurityTokenHandler();  
                var key = Encoding.ASCII.GetBytes(_configuration["Jwt:Key"]);  
                tokenHandler.ValidateToken(token, new TokenValidationParameters  
                {  
                    ValidateIssuerSigningKey = true,  
                    IssuerSigningKey = new SymmetricSecurityKey(key),  
                    ValidateIssuer = false,  
                    ValidateAudience = false,  
                    // set clockskew to zero so tokens expire exactly at token expiration time (instead of 5 minutes later)  
                    ClockSkew = TimeSpan.Zero  
                }, out SecurityToken validatedToken);  
                  
                var jwtToken = (JwtSecurityToken)validatedToken;  
                  
                //get the user name and role from the JWT token.  
                var username = jwtToken.Claims.First(x => x.Type == "username").Value;  
                var role = jwtToken.Claims.First(x => x.Type == "role").Value;  
    
    
                var userClaims = new List<Claim>()  
                {  
                    new Claim("UserName", username),   
                    new Claim("Role", role)  
                 };  
    
                var userIdentity = new ClaimsIdentity(userClaims, "User Identity");  
    
                var userPrincipal = new ClaimsPrincipal(new[] { userIdentity });  
                   
                // attach account to context on successful jwt validation   
                //var user = new MVCWebApplication.Data.User();  
                //user.UserName = "******@hotmail.com";  
                //context.Items["User"] = user;  
    
                context.SignInAsync(userPrincipal);  
            }  
            catch (Exception ex)  
            {  
                // do nothing if jwt validation fails  
                // account is not attached to context so request won't have access to secure routes  
                throw new Exception(ex.Message);  
            }  
        }  
    }  
    

    Register the JWTMiddleware in the Configure method:

            app.UseAuthentication();  
            app.UseAuthorization();  
            app.UseMiddleware<JWTMiddleware>();  
    

    In the MVC controller action method:

        [Authorize(AuthenticationSchemes = Microsoft.AspNetCore.Authentication.JwtBearer.JwtBearerDefaults.AuthenticationScheme)]  
        public IActionResult Index()  
        {  
            return View(_context.Students.ToList());  
        }  
    

    and in the View page:

    @{  
        if (User.Claims.FirstOrDefault(c => c.Type.Contains("role"))?.Value == "Admin")  
        {   
            <h2>@User.Claims.FirstOrDefault(c => c.Type.Contains("username")).Value</h2>  
            <h2>@User.Claims.FirstOrDefault(c => c.Type.Contains("role")).Value</h2>  
        }  
    }  
    

    The result as below: When calling the action method with JWT token, if the user's role is "Admin", it will show the username and role name.

    137343-image.png

    Reference: Create And Validate JWT Token In .NET 5.0


    If the answer is helpful, please click "Accept Answer" and upvote it.
    Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

    Best regards,
    Dillion

    1 person found this answer helpful.
    0 comments No comments

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.