Reputation: 368
I am trying to build a permission based Authorization for Asp.net Core while I am moving to core from .net framework. I built an Authorization system based on my needs(using Identity). Basically I am adding Claims to Roles and Users have roles. I built checkboxes for assigning roles to user and assigning claims to roles. Everything works well but here is my question:
While the system is working, let's say user1 has "Admin Role". user1 can access the pages based on the policies which are using his roles->claims. The problem starts here. While user1 is logged in, if I change the claims of "Admin" role, user1 won't be effected until he/she log off and login again.
Anyone has an idea to solve this problem?
Upvotes: 0
Views: 550
Reputation: 1680
The solution seems to work... but let me raise up a caution a bit...
Since you have to check the permission on database for every client request (which will have a real burden to the system). I know it seems like you're building classic mono app. But the server will still suffer from coming back and forth database hard.
Imagine you display a report section that user usually access it frequently, but on some nice day... the browser blank out, or pop-up some dialog that she doesn't have permission to using this anymore. That's could cause real issue cause user only use what they need at the very moment. What'll happen if it's 10 minutes to the meeting and an assistance needed to print out some report and that pop-up ? (from my experienced lesson (XD)).
So I highly suggest that, on app deployemnt and user login, take all their role and claims from database once and cache them somewhere (like IMemoryCache
, since we are targeting classic mono app), then check the claim on caches afterward.
Everytime user permission changed, update the cache, and log the user out right at that moment. If something bad happen. User would yelling at the person who setting the permission, not us as developers.
Seems like you have spend a few continuously hours to complete your own decent solution since last time.
Good work mate
Upvotes: 1
Reputation: 368
Okay. I came up with a solution.
internal class PermissionAuthorizationHandler : AuthorizationHandler<PermissionRequirement>
{
UserManager<User> _userManager;
RoleManager<IdentityRole> _roleManager;
public PermissionAuthorizationHandler(UserManager<User> userManager, RoleManager<IdentityRole> roleManager)
{
_userManager = userManager;
_roleManager = roleManager;
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, PermissionRequirement requirement)
{
if (context.User.Identity.Name == null)
{
return;
}
// Get all the roles the user belongs to and check if any of the roles has the permission required
// for the authorization to succeed.
var user = await _userManager.GetUserAsync(context.User);
var userRoleNames = await _userManager.GetRolesAsync(user);
var userRoles = _roleManager.Roles.Where(x => userRoleNames.Contains(x.Name));
foreach (var role in userRoles)
{
var roleClaims = await _roleManager.GetClaimsAsync(role);
var permissions = roleClaims.Where(x => x.Type == CustomClaimTypes.Permission &&
x.Value == requirement.Permission)
.Select(x => x.Value);
if (permissions.Any())
{
context.Succeed(requirement);
return;
}
}
}
}
and then we call this in startup.cs
services.AddScoped<IAuthorizationHandler, PermissionAuthorizationHandler>();
For more detailed answer please check: https://www.zehntec.com/blog/permission-based-authorization-in-asp-net-core/
Upvotes: 0