造轮子之权限管理

上文已经完成了自定义授权策略,那么接下来就得完善我们的权限管理了。不然没有数据,如何鉴权~

表设计

创建我们的表实体类:

namespace Wheel.Domain.Permissions {     public class PermissionGrant : Entity<Guid>     {         public string Permission { get; set; }         public string GrantType { get; set; }         public string GrantValue { get; set; }     } } 

Permission表示权限名称,结构为"{controllerName}:{actionName}"。
GrantType表示权限类型,如角色权限则R表示,方便后续在新增别的权限类型时可以灵活扩展。
GrantValue则表示权限类型对应的值,比如GrantType是R时,GrantValue是admin则表示admin角色的授权。

修改DbContext

在WheelDbContext添加代码:

#region Permission public DbSet<PermissionGrant> PermissionGrants { get; set; } #endregion 
void ConfigurePermissionGrants(ModelBuilder builder) {     builder.Entity<PermissionGrant>(b =>     {         b.HasKey(o => o.Id);         b.Property(o => o.Permission).HasMaxLength(128);         b.Property(o => o.GrantValue).HasMaxLength(128);         b.Property(o => o.GrantType).HasMaxLength(32);     }); } 

在OnModelCreating添加ConfigurePermissionGrants方法。

protected override void OnModelCreating(ModelBuilder builder) {     base.OnModelCreating(builder);      ConfigurePermissionGrants(builder); } 

接下来执行数据库迁移命令即可完成表创建。

实现权限管理

接下来就是实现我们的权限管理功能。
我们的PermissionManageAppService只需定义三个API即可满足管理需求。分别是获取当前用户所有权限,修改用户权限,获取指定角色权限。

namespace Wheel.Services.PermissionManage {     public interface IPermissionManageAppService : ITransientDependency     {         Task<R<List<GetAllPermissionDto>>> GetPermission();         Task<R> UpdatePermission(UpdatePermissionDto dto);         Task<R<List<GetAllPermissionDto>>> GetRolePermission(string RoleName);     } } 

具体实现代码如下:

namespace Wheel.Services.PermissionManage {     public class PermissionManageAppService : WheelServiceBase, IPermissionManageAppService     {         private readonly IBasicRepository<PermissionGrant, Guid> _permissionGrantRepository;         private readonly RoleManager<Role> _roleManager;         private readonly XmlCommentHelper _xmlCommentHelper;         public PermissionManageAppService(XmlCommentHelper xmlCommentHelper, IBasicRepository<PermissionGrant, Guid> permissionGrantRepository, RoleManager<Role> roleManager)         {             _xmlCommentHelper = xmlCommentHelper;             _permissionGrantRepository = permissionGrantRepository;             _roleManager = roleManager;         }         public async Task<R<List<GetAllPermissionDto>>> GetPermission()         {             var result = await GetAllDefinePermission();             if (CurrentUser.IsInRoles("admin"))             {                 result.ForEach(p => p.Permissions.ForEach(a => a.IsGranted = true));             }             else             {                 var grantPermissions = (await _permissionGrantRepository                     .SelectListAsync(a => a.GrantType == "R" && CurrentUser.Roles.Contains(a.GrantValue), a => a.Permission))                     .Distinct().ToList();                  foreach (var group in result)                 {                     foreach (var permission in group.Permissions)                     {                         if (grantPermissions.Any(b => b == $"{group.Group}:{permission.Name}"))                             permission.IsGranted = true;                         else                             permission.IsGranted = false;                     }                 }             }             return new R<List<GetAllPermissionDto>>(result);         }         public async Task<R<List<GetAllPermissionDto>>> GetRolePermission(string RoleName)         {             var result = await GetAllDefinePermission();              var grantPermissions = (await _permissionGrantRepository                 .SelectListAsync(a => a.GrantType == "R" && RoleName == a.GrantValue, a => a.Permission))                 .Distinct().ToList();              foreach (var group in result)             {                 foreach (var permission in group.Permissions)                 {                     if (grantPermissions.Any(b => b == $"{group.Group}:{permission.Name}"))                         permission.IsGranted = true;                     else                         permission.IsGranted = false;                 }             }              return new R<List<GetAllPermissionDto>>(result);         }         public async Task<R> UpdatePermission(UpdatePermissionDto dto)         {             if(dto.Type == "R")              {                 var exsit = await _roleManager.RoleExistsAsync(dto.Value);                 if (!exsit)                     throw new BusinessException(ErrorCode.RoleNotExist, "RoleNotExist")                         .WithMessageDataData(dto.Value);             }             using (var tran = await UnitOfWork.BeginTransactionAsync())             {                 await _permissionGrantRepository.DeleteAsync(a => a.GrantType == dto.Type && a.GrantValue == dto.Value);                 await _permissionGrantRepository.InsertManyAsync(dto.Permissions.Select(a=> new PermissionGrant                  {                     Id = GuidGenerator.Create(),                     GrantType = dto.Type,                     GrantValue = dto.Value,                     Permission = a                 }).ToList());                 await DistributedCache.SetAsync($"Permission:{dto.Type}:{dto.Value}", dto.Permissions);                 await tran.CommitAsync();             }             return new R();         }          private ValueTask<List<GetAllPermissionDto>> GetAllDefinePermission()         {              var result = MemoryCache.Get<List<GetAllPermissionDto>>("AllDefinePermission");             if (result == null)             {                 result = new List<GetAllPermissionDto>();                 var apiDescriptionGroupCollectionProvider = ServiceProvider.GetRequiredService<IApiDescriptionGroupCollectionProvider>();                 var apiDescriptionGroups = apiDescriptionGroupCollectionProvider.ApiDescriptionGroups.Items.SelectMany(group => group.Items)                     .Where(a => a.ActionDescriptor is ControllerActionDescriptor)                     .GroupBy(a => (a.ActionDescriptor as ControllerActionDescriptor).ControllerTypeInfo);                  foreach (var apiDescriptions in apiDescriptionGroups)                 {                     var permissionGroup = new GetAllPermissionDto();                     var controllerTypeInfo = apiDescriptions.Key;                      var controllerAllowAnonymous = controllerTypeInfo.GetAttribute<AllowAnonymousAttribute>();                      var controllerComment = _xmlCommentHelper.GetTypeComment(controllerTypeInfo);                      permissionGroup.Group = controllerTypeInfo.Name;                     permissionGroup.Summary = controllerComment;                     foreach (var apiDescription in apiDescriptions)                     {                         var method = controllerTypeInfo.GetMethod(apiDescription.ActionDescriptor.RouteValues["action"]);                         var actionAllowAnonymous = method.GetAttribute<AllowAnonymousAttribute>();                         var actionAuthorize = method.GetAttribute<AuthorizeAttribute>();                         if ((controllerAllowAnonymous == null && actionAllowAnonymous == null) || actionAuthorize != null)                         {                             var methodComment = _xmlCommentHelper.GetMethodComment(method);                             permissionGroup.Permissions.Add(new PermissionDto { Name = method.Name, Summary = methodComment });                         }                     }                     if (permissionGroup.Permissions.Count > 0)                         result.Add(permissionGroup);                 }                 MemoryCache.Set("AllDefinePermission", result);             }             return ValueTask.FromResult(result);         }     } } 

控制器代码如下:

namespace Wheel.Controllers {     /// <summary>     /// 权限管理     /// </summary>     [Route("api/[controller]")]     [ApiController]     public class PermissionManageController : WheelControllerBase     {         private readonly IPermissionManageAppService _permissionManageAppService;         public PermissionManageController(IPermissionManageAppService permissionManageAppService)         {             _permissionManageAppService = permissionManageAppService;         }         /// <summary>         /// 获取所有权限         /// </summary>         /// <returns></returns>         [HttpGet()]         public Task<R<List<GetAllPermissionDto>>> GetPermission()         {             return _permissionManageAppService.GetPermission();         }         /// <summary>         /// 获取指定角色权限         /// </summary>         /// <returns></returns>         [HttpGet("{role}")]         public Task<R<List<GetAllPermissionDto>>> GetRolePermission(string role)         {             return _permissionManageAppService.GetRolePermission(role);         }         /// <summary>         /// 修改权限         /// </summary>         /// <param name="dto"></param>         /// <returns></returns>         [HttpPut]         public async Task<R> UpdatePermission(UpdatePermissionDto dto)         {             return await _permissionManageAppService.UpdatePermission(dto);         }     } } 

通过读取XML注释文件,自动生成Controller和Action的注释名称。
将权限配置信息写入缓存,提供给PermissionChecker使用。
权限返回的结构如下:

namespace Wheel.Services.PermissionManage.Dtos {     public class GetAllPermissionDto     {         public string Group { get; set; }          public string Summary { get; set; }           public List<PermissionDto> Permissions { get; set; } = new ();              }     public class PermissionDto     {         public string Name { get; set; }         public string Summary { get; set; }          public bool IsGranted { get; set; }     } } 

使用Postman测试API,可以看到,获取了我们的权限信息列表,按照Controller分组,细分到每一个Action,summary是我们XML注释的内容。
造轮子之权限管理

到这我们就完成了权限管理的API。

轮子仓库地址https://github.com/Wheel-Framework/Wheel
欢迎进群催更。

造轮子之权限管理

发表评论

评论已关闭。

相关文章