first commit
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
namespace OpenWarehouse.auth.api.Common.PrivilageManager;
|
||||
|
||||
public static class GlobalPrivilage
|
||||
{
|
||||
public enum Privilege
|
||||
{
|
||||
GlobalAdmin,
|
||||
GlobalManageUser,
|
||||
GlobalCreateUser,
|
||||
GlobalDeleteUser,
|
||||
GlobalEditUser,
|
||||
GlobalManageRole,
|
||||
GlobalCreateRole,
|
||||
GlobalDeleteRole,
|
||||
GlobalEditRole,
|
||||
GlobalDeleteExpiredToken,
|
||||
GlobalDeactivateUserToken,
|
||||
GlobalUser
|
||||
}
|
||||
|
||||
private static readonly Dictionary<Privilege, string> PrivilegeToStringMap = new()
|
||||
{
|
||||
{ Privilege.GlobalAdmin, "Auth-Admin" },
|
||||
{ Privilege.GlobalManageUser, "Auth-User-Manage" },
|
||||
{ Privilege.GlobalCreateUser, "Auth-User-Create" },
|
||||
{ Privilege.GlobalDeleteUser, "Auth-User-Delete" },
|
||||
{ Privilege.GlobalEditUser, "Auth-User-Edit" },
|
||||
{ Privilege.GlobalManageRole, "Auth-Role-Manage" },
|
||||
{ Privilege.GlobalCreateRole, "Auth-Role-Create-" },
|
||||
{ Privilege.GlobalDeleteRole, "Auth-Role-Delete" },
|
||||
{ Privilege.GlobalEditRole, "Auth-Role-Edit" },
|
||||
{ Privilege.GlobalDeleteExpiredToken, "Auth-Delete-Expired-Token" },
|
||||
{ Privilege.GlobalDeactivateUserToken, "Auth-Deactivate-User-Token" },
|
||||
{ Privilege.GlobalUser, "Auth-User" }
|
||||
};
|
||||
|
||||
|
||||
private static readonly Dictionary<Privilege, List<Privilege>> PrivilegeMap = new()
|
||||
{
|
||||
{ Privilege.GlobalAdmin, new List<Privilege> { Privilege.GlobalAdmin } },
|
||||
{ Privilege.GlobalManageUser, new List<Privilege> { Privilege.GlobalAdmin, Privilege.GlobalManageUser } },
|
||||
{ Privilege.GlobalCreateUser, new List<Privilege> { Privilege.GlobalAdmin, Privilege.GlobalManageUser, Privilege.GlobalCreateUser } },
|
||||
{ Privilege.GlobalDeleteUser, new List<Privilege> { Privilege.GlobalAdmin, Privilege.GlobalManageUser, Privilege.GlobalDeleteUser } },
|
||||
{ Privilege.GlobalEditUser, new List<Privilege> { Privilege.GlobalAdmin, Privilege.GlobalManageUser, Privilege.GlobalEditUser } },
|
||||
{ Privilege.GlobalManageRole, new List<Privilege> { Privilege.GlobalAdmin, Privilege.GlobalManageRole } },
|
||||
{ Privilege.GlobalCreateRole, new List<Privilege> { Privilege.GlobalAdmin, Privilege.GlobalManageRole, Privilege.GlobalCreateRole } },
|
||||
{ Privilege.GlobalDeleteRole, new List<Privilege> { Privilege.GlobalAdmin, Privilege.GlobalManageRole, Privilege.GlobalDeleteRole } },
|
||||
{ Privilege.GlobalEditRole, new List<Privilege> { Privilege.GlobalAdmin, Privilege.GlobalManageRole, Privilege.GlobalEditRole } },
|
||||
{ Privilege.GlobalDeactivateUserToken, new List<Privilege> { Privilege.GlobalAdmin, Privilege.GlobalDeactivateUserToken } },
|
||||
{ Privilege.GlobalDeleteExpiredToken, new List<Privilege> { Privilege.GlobalAdmin, Privilege.GlobalDeleteExpiredToken } },
|
||||
{ Privilege.GlobalUser , GetAllPrivilages()}
|
||||
};
|
||||
|
||||
|
||||
public static List<string> GetPrivilegesFor(this Privilege privilegeKey)
|
||||
{
|
||||
var privilegeStrings = new List<string>();
|
||||
|
||||
if (PrivilegeMap.TryGetValue(privilegeKey, out var privileges))
|
||||
{
|
||||
foreach (var privilege in privileges)
|
||||
{
|
||||
if (PrivilegeToStringMap.TryGetValue(privilege, out var privilegeString))
|
||||
{
|
||||
privilegeStrings.Add(privilegeString);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return privilegeStrings;
|
||||
}
|
||||
|
||||
public static string? GetStringForPrivilege(this Privilege privilege)
|
||||
{
|
||||
|
||||
bool isSuccess = PrivilegeToStringMap.TryGetValue(privilege, out var privilegeString);
|
||||
|
||||
if (isSuccess)
|
||||
{
|
||||
return privilegeString;
|
||||
}
|
||||
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<string> GatherPrivilegeStrings()
|
||||
{
|
||||
var privilegeStrings = new List<string>();
|
||||
|
||||
foreach (var privilege in GetAllPrivilages())
|
||||
{
|
||||
var privilegeString = privilege.GetStringForPrivilege();
|
||||
if (privilegeString != null)
|
||||
{
|
||||
privilegeStrings.Add(privilegeString);
|
||||
}
|
||||
}
|
||||
|
||||
return privilegeStrings;
|
||||
}
|
||||
|
||||
public static List<Privilege> GetAllPrivilages()
|
||||
{
|
||||
var allPrivileges = new List<Privilege>();
|
||||
foreach (var privilege in Enum.GetValues(typeof(Privilege)))
|
||||
{
|
||||
allPrivileges.Add((Privilege)privilege);
|
||||
}
|
||||
|
||||
return allPrivileges;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.IdentityModel.JsonWebTokens;
|
||||
|
||||
namespace OpenWarehouse.auth.api.Common.PrivilageManager;
|
||||
|
||||
/// <summary>
|
||||
/// Attribute to enforce privilege-based authorization.
|
||||
/// </summary>
|
||||
public class HasPrivilegeAttribute : Attribute, IAsyncAuthorizationFilter
|
||||
{
|
||||
private GlobalPrivilage.Privilege[] Privileges { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="HasPrivilegeAttribute"/> class with one or more required privileges.
|
||||
/// </summary>
|
||||
/// <param name="privileges">The privileges required to access the resource.</param>
|
||||
public HasPrivilegeAttribute(params GlobalPrivilage.Privilege[] privileges)
|
||||
{
|
||||
Privileges = privileges;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Performs the privilege check during authorization.
|
||||
/// </summary>
|
||||
/// <param name="context">The authorization filter context.</param>
|
||||
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
|
||||
{
|
||||
var userActionId = context.HttpContext.User.FindFirstValue(JwtRegisteredClaimNames.Sub);
|
||||
|
||||
var userManager = context.HttpContext.RequestServices.GetRequiredService<UserManager<ApplicationUser>>();
|
||||
var privilegeManager = context.HttpContext.RequestServices.GetRequiredService<PrivilegeManager>();
|
||||
|
||||
if (userActionId != null)
|
||||
{
|
||||
var userAction = await userManager.FindByIdAsync(userActionId);
|
||||
if (userAction == null ||
|
||||
!await UserHasAnyRequiredPrivilege(privilegeManager, userAction))
|
||||
{
|
||||
context.Result = new ContentResult
|
||||
{
|
||||
StatusCode = StatusCodes.Status403Forbidden,
|
||||
Content = "Access Denied: You do not have the required privileges to perform this action.",
|
||||
ContentType = "text/plain"
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the user has at least one of the required privileges.
|
||||
/// </summary>
|
||||
/// <param name="privilegeManager">The privilege manager service.</param>
|
||||
/// <param name="user">The user to check privileges for.</param>
|
||||
/// <returns>True if the user has any required privilege; otherwise, false.</returns>
|
||||
private async Task<bool> UserHasAnyRequiredPrivilege(PrivilegeManager privilegeManager, ApplicationUser user)
|
||||
{
|
||||
foreach (var privilege in Privileges)
|
||||
{
|
||||
if (await privilegeManager.UserHasGlobalPrivilage(user, privilege))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
using OpenWarehouse.auth.lib.Model.Service;
|
||||
|
||||
namespace OpenWarehouse.auth.api.Common.PrivilageManager;
|
||||
|
||||
public interface IPrivilageManager
|
||||
{
|
||||
|
||||
public Task<List<string?>> GetUserPrivilage(ApplicationUser user);
|
||||
public Task<List<string>?> GetRolePrivilage(ApplicationRole role);
|
||||
|
||||
public Task AddRolePrivilage(ApplicationRole role, string privilage);
|
||||
public Task DeleteRolePrivilage(ApplicationRole role, string privilage);
|
||||
|
||||
public Task<bool> RoleHasPrivilage(ApplicationRole role, string privilage);
|
||||
public Task<bool> UserHasPrivilage(ApplicationUser user, string privilage);
|
||||
public Task<bool> UserHasGlobalPrivilage(ApplicationUser user, GlobalPrivilage.Privilege privilege);
|
||||
|
||||
public Task<RolePrivilage?> GetPrivilageByNameIfDontExistCreateAsync(string privilage);
|
||||
|
||||
public Task<RolePrivilage?> GetPrivilageByName(string privilage);
|
||||
|
||||
public Task<CreateServiceRoleResult> CreatePrivageAsync(string privilage);
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
using OpenWarehouse.auth.lib.Model.Service;
|
||||
|
||||
namespace OpenWarehouse.auth.api.Common.PrivilageManager;
|
||||
|
||||
public class PrivilegeManager(ApplicationDbContext context,
|
||||
RoleManager<ApplicationRole> roleManager,
|
||||
UserManager<ApplicationUser> userManager,
|
||||
ILogger<PrivilegeManager> logger) : IPrivilageManager
|
||||
{
|
||||
public async Task<List<string?>> GetUserPrivilage(ApplicationUser user)
|
||||
{
|
||||
var roles = await userManager.GetRolesAsync(user);
|
||||
List<string?> privilages = [];
|
||||
|
||||
foreach (var role in roles)
|
||||
{
|
||||
var roleObj = await context.Roles.Include(applicationRole => applicationRole.Privilege).FirstOrDefaultAsync(applicationRole =>
|
||||
applicationRole.NormalizedName.Equals(roleManager.NormalizeKey(role)));
|
||||
|
||||
if (roleObj != null && roleObj.IsGlobalAdmin)
|
||||
privilages.Add("Admin");
|
||||
|
||||
if (roleObj is { Privilege: not null })
|
||||
privilages.AddRange(roleObj.Privilege.Select(privilage => privilage?.Privilage).ToList());
|
||||
}
|
||||
|
||||
return privilages.Distinct().ToList();
|
||||
}
|
||||
|
||||
public async Task<List<string>?> GetRolePrivilage(ApplicationRole role)
|
||||
{
|
||||
|
||||
List<string>? privilageList = [];
|
||||
if (role.IsGlobalAdmin)
|
||||
{
|
||||
privilageList.Add("Admin");
|
||||
return privilageList;
|
||||
}
|
||||
|
||||
var privilage = await context.RolePrivilages
|
||||
.Where(rolePrivilage => rolePrivilage.Roles.Any(applicationRole => applicationRole == role)).ToListAsync();
|
||||
|
||||
if (privilage != null)
|
||||
privilageList = privilage.Select(privilage => privilage.Privilage).Distinct().ToList();
|
||||
|
||||
return privilageList;
|
||||
}
|
||||
|
||||
public async Task AddRolePrivilage(ApplicationRole role, string privilage)
|
||||
{
|
||||
var privilageObj = await context.RolePrivilages.Include(rolePrivilage => rolePrivilage.Roles)
|
||||
.FirstOrDefaultAsync(rolePrivilage => rolePrivilage.Privilage.Equals(privilage));
|
||||
|
||||
if(privilageObj is { Roles: not null }
|
||||
&& !privilageObj.Roles.Any(applicationRole => applicationRole.Id == role.Id))
|
||||
privilageObj.Roles.Add(role);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
public async Task DeleteRolePrivilage(ApplicationRole role, string privilage)
|
||||
{
|
||||
var privilageToDelete = await context.RolePrivilages
|
||||
.Where(rolePrivilage => rolePrivilage.Privilage == privilage &&
|
||||
rolePrivilage.Roles.Any(applicationRole => applicationRole.Id == role.Id))
|
||||
.FirstOrDefaultAsync();
|
||||
|
||||
if (privilageToDelete != null)
|
||||
{
|
||||
context.RolePrivilages.Remove(privilageToDelete);
|
||||
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
}
|
||||
|
||||
public async Task<bool> RoleHasPrivilage(ApplicationRole role, string privilage)
|
||||
{
|
||||
if (role.IsGlobalAdmin) return true;
|
||||
|
||||
if (role.Privilege == null) return false;
|
||||
|
||||
|
||||
|
||||
return role.Privilege.Any(rolePrivilage => rolePrivilage.Privilage == privilage);
|
||||
}
|
||||
|
||||
public async Task<bool> UserHasPrivilage(ApplicationUser user, string privilage)
|
||||
{
|
||||
var rolesName = await userManager.GetRolesAsync(user);
|
||||
foreach (var roleName in rolesName)
|
||||
{
|
||||
var role = await roleManager.FindByNameAsync(roleName);
|
||||
if (role == null) return false;
|
||||
return await RoleHasPrivilage(role, privilage);
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public async Task<bool> UserHasGlobalPrivilage(ApplicationUser user, GlobalPrivilage.Privilege privilage)
|
||||
{
|
||||
var have = false;
|
||||
|
||||
foreach (var priv in privilage.GetPrivilegesFor())
|
||||
{
|
||||
have = await UserHasPrivilage(user, priv);
|
||||
if (have) break;
|
||||
}
|
||||
|
||||
return have;
|
||||
}
|
||||
|
||||
public async Task<RolePrivilage?> GetPrivilageByNameIfDontExistCreateAsync(string privilageName)
|
||||
{
|
||||
var privilage = await GetPrivilageByName(privilageName);
|
||||
|
||||
if (privilage == null)
|
||||
{
|
||||
privilage = new RolePrivilage(privilage: privilageName);
|
||||
context.RolePrivilages.Add(privilage);
|
||||
await context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
return privilage;
|
||||
}
|
||||
|
||||
public async Task<RolePrivilage?> GetPrivilageByName(string privilage)
|
||||
{
|
||||
return await context.RolePrivilages.FirstOrDefaultAsync(q => q.Privilage == privilage);
|
||||
}
|
||||
|
||||
public async Task<CreateServiceRoleResult> CreatePrivageAsync(string privilage)
|
||||
{
|
||||
try
|
||||
{
|
||||
var privilageObj = new RolePrivilage() { Privilage = privilage };
|
||||
|
||||
var entityEntry = context.RolePrivilages.Add(privilageObj);
|
||||
|
||||
if (await context.SaveChangesAsync() > 0) return new CreateServiceRoleResult(isSuccessed: true, null) { };
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Dictionary<string, string> errors = new Dictionary<string, string>();
|
||||
|
||||
errors[e.Source ?? "Uknow"] = e.Message;
|
||||
return new CreateServiceRoleResult(false, errors);
|
||||
|
||||
}
|
||||
|
||||
return new CreateServiceRoleResult(false, null);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user