Check JWT token exists in memory cache before executing the codes in the API

628 Views Asked by At

I'm working on a .Net Core project with hundreds of APIs in it.

The APIs accept JWT token to authorize.

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]

As JWT tokens cannot be destroyed until the expiration time is over, I need to make sure that the token gets unsuable when the user logsout.

I stored the JWT token with key in the memory cache at it's creation.

memoryCache.Set(ob.MailId, Token.Token);

I want to allow the code execution only if the token exists in the memory cache, so that, when the user logsout, I'll remove the token from the memory cache, then the API will be inaccessible with the same token.

I don't want to put condition check in every APIs and I do not have much detail knowledge with Authorization either.

Is there any way to put a condition along with the header such a way that if the condition fails, it hits the UnauthorizedAccessException?

Please suggest me an efficient way to execute this.

2

There are 2 best solutions below

1
Ruikai Feng On BEST ANSWER

We use http 401 statue code instead of UnauthorizedAccessException to indicate user is unauthenticated in usual.

You could decide where to get the token when you configure JwtAuthentication,a minimal example:

in Program.cs:

builder.Services.AddMemoryCache();
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(op =>
{
    op.TokenValidationParameters = new TokenValidationParameters
    {
        ValidIssuer = builder.Configuration["Jwt:Issuer"],
        ValidAudience = builder.Configuration["Jwt:Audience"],
        IssuerSigningKey = new SymmetricSecurityKey
        (Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])),
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = false,
        ValidateIssuerSigningKey = true
    };
    op.Events=new JwtBearerEvents()
    {

          
        OnMessageReceived = context =>
        {
            var cache = context.HttpContext.RequestServices.GetService<IMemoryCache>();
            var success = cache.TryGetValue("JwtToken", out var token);
            if (success)
            {
                // you could decide where to get the token here
                context.Token = token.ToString();
            }
            
            return Task.CompletedTask;
        }
    };
});

AuthController:

[Route("api/[controller]")]
    [ApiController]
    public class MyAuthController : ControllerBase
    {
        private readonly IMemoryCache _cache;
        private readonly IConfiguration _configuration;
        public MyAuthController(IMemoryCache cache, IConfiguration configuration)
        {
            _cache = cache;
            _configuration = configuration;
        }

        [HttpGet("Login")]
        public IActionResult Login()
        {

            var issuer = _configuration["Jwt:Issuer"];
            var audience = _configuration["Jwt:Audience"];
            var key = Encoding.ASCII.GetBytes(_configuration["Jwt:Key"]);
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new[]
                {

                new Claim(ClaimTypes.Name, "Zhang"),
                new Claim(ClaimTypes.Role, "Admin"),

                         }),
                Expires = DateTime.UtcNow.AddMinutes(5),
                Issuer = issuer,
                Audience = audience,
                SigningCredentials = new SigningCredentials
                (new SymmetricSecurityKey(key),
                SecurityAlgorithms.HmacSha512Signature)
            };
            var tokenHandler = new JwtSecurityTokenHandler();
            var token = tokenHandler.CreateToken(tokenDescriptor);
            var jwtToken = tokenHandler.WriteToken(token);
            var stringToken = tokenHandler.WriteToken(token);

            _cache.Set("JwtToken", stringToken);
            return Ok();
        }

        [HttpGet("Logout")]
        public IActionResult Logout()
        {
            _cache.Remove("JwtToken");
            return Ok();
        }
    }

Result: enter image description here

Here's a document related with ASP.NET Core authentication,Hopes help

0
Miguel Morgado On

You could create a custom AuthorizationFilter by inheriting the IAuthorizationFilter interface, here's an example.

using Microsoft.AspNetCore.Mvc.Filters;

namespace Example.Web.Attributes
{
    public class CustomAuthFilter : IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            // Your validation logic here
            if (...)
            {
                return;
            }
            else
            {
                throw new UnauthorizedAccessException();
            }
        }
    }
}

After that just use the filter on a controller or endpoint.