I'm working on an ASP.NET Core web application and implementing JWT authorization using a custom attribute [JwtAuthorize]. The goal is to ensure that specific controller actions are protected and require a valid JWT token for access. However, I'm encountering an issue where the [JwtAuthorize] attribute is not triggering for the controller actions where I've applied it.
Here's the setup I have:
I created a custom JwtAuthorizeAttribute class that extends AuthorizeAttribute and implements IAsyncAuthorizationFilter:
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
public class JwtAuthorizeAttribute : AuthorizeAttribute, IAsyncAuthorizationFilter
{
public bool ApplyAuthorization { get; set; } = false;
public JwtAuthorizeAttribute(bool applyAuthorization = false)
{
ApplyAuthorization = applyAuthorization;
}
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
if (ApplyAuthorization)
{
var httpContext = context.HttpContext;
var token = httpContext.Session.GetString("JwtToken");
if (!string.IsNullOrEmpty(token))
{
var tokenHandler = new JwtSecurityTokenHandler();
var jwtToken = tokenHandler.ReadJwtToken(token);
if (jwtToken.ValidTo > DateTime.UtcNow) // Check token expiration
{
httpContext.Request.Headers.Add("Authorization", $"Bearer {token}");
}
else
{
// Redirect to login or handle expired token
context.Result = new UnauthorizedResult();
}
}
else
{
// Redirect to login or handle unauthorized access
context.Result = new UnauthorizedResult();
}
}
return;
}
}
In my Startup.cs, I registered the JwtAuthorizeAttribute as a scoped service:
services.AddCors();
services.AddControllersWithViews();
services.AddScoped<AuthService>();
services.AddHttpClient();
services.AddHttpContextAccessor();
services.AddScoped<JwtAuthorizeAttribute>();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateIssuerSigningKey = true,
ValidIssuer = Configuration["AppSettings:ValidIssuer"],
ValidAudience = Configuration["AppSettings:ValidAudience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(Configuration["AppSettings:Secret"]))
};
});
services.AddSession(options =>
{
options.Cookie.IsEssential = true;
options.IdleTimeout = TimeSpan.FromMinutes(60);
});
services.AddMvcCore(options =>
{
options.Filters.Add(typeof(JwtAuthorizeAttribute));
});
I added the [JwtAuthorize] attribute to a specific controller action that I want to protect:
public IActionResult Index()
{
return View();
}
[JwtAuthorize(ApplyAuthorization = true)] // Apply authorization
public IActionResult Dashboard ()
{
return View();
}
The problem is that when I access the Dashboard action, the [JwtAuthorize] attribute does not seem to be triggering and it returns 401 response immediately. I verified this by placing breakpoints within the OnAuthorizationAsync method of the JwtAuthorizeAttribute class, but the breakpoints are not hit when accessing the Dashboard action.
I have double-checked that the JWT token is valid and stored correctly in the session. Additionally, I noticed that the [JwtAuthorize] attribute works as expected for other actions where I didn't explicitly apply the attribute.
My question is: Why is the [JwtAuthorize] attribute not triggering for the Dashboard action, even though it is being triggered for other actions?
Any insights or suggestions on how to troubleshoot and resolve this issue would be greatly appreciated.