上一篇文章我们一起编写了自动添加接口地址,这一篇文章我们补充简易权限中的自动添加角色可访问接口。
一 实现
首先,我们Initialization
文件夹下新建AddRolePath
类,这个类用于初始化数据库中SysRoleUr
l表,代码如下:
using System.Reflection;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using SporeAccounting.Controllers;
using SporeAccounting.Models;
using SporeAccounting.Server.Interface;namespace SporeAccounting.Initialization;/// <summary>
/// 添加角色路径
/// </summary>
public static class AddRolePath
{/// <summary>/// 初始化/// </summary>/// <param name="serviceProvider"></param>public static void Init(IServiceProvider serviceProvider){using (var scope = serviceProvider.CreateScope()){var sysRoleUrlService = scope.ServiceProvider.GetService<ISysRoleUrlServer>();//1. 获取所有的URLvar sysUrlServer = scope.ServiceProvider.GetService<ISysUrlServer>();var urls = sysUrlServer?.Query();//2. 获取所有的角色var roleService = scope.ServiceProvider.GetService<ISysRoleServer>();var roles = roleService.Query();//3. 解析每个Controller的Authorize特性中Roles的角色var controllerRoles = new Dictionary<string, List<string>>();foreach (var controller in Assembly.GetExecutingAssembly().GetTypes().Where(t => typeof(ControllerBase).IsAssignableFrom(t))){var authorizeAttributes = controller.GetCustomAttributes<AuthorizeAttribute>();foreach (var attribute in authorizeAttributes){var controllerName = controller.Name.Replace("Controller", "");if (!controllerRoles.ContainsKey(controllerName)){controllerRoles[controllerName] = new List<string>();}controllerRoles[controllerName].AddRange(attribute.Roles.Split(','));}}List<SysRoleUrl> sysRoleUrls = new List<SysRoleUrl>();//4. 解析每个Controller的Action的特性如果有AllowAnonymous则跳过,反之拼接Controller和Action生产接口地址foreach (var controller in Assembly.GetExecutingAssembly().GetTypes().Where(type => typeof(BaseController).IsAssignableFrom(type))){var actions = controller.GetMethods().Where(m => m.IsPublic && !m.GetCustomAttributes<NonActionAttribute>().Any());foreach (var action in actions){if (action.GetCustomAttributes<AllowAnonymousAttribute>().Any()){continue;}var routeAttribute = controller.GetCustomAttribute<RouteAttribute>();var actionRouteAttribute = action.GetCustomAttribute<RouteAttribute>();if (routeAttribute == null || actionRouteAttribute == null){continue;}var controllerRoute = routeAttribute.Template;var controllerName = controller.Name.Replace("Controller", "");if (controllerRoute.Contains("[controller]")){controllerRoute =controllerRoute.Replace("[controller]", controllerName);}var actionName = actionRouteAttribute.Template;if (actionName.Contains("[action]")){actionName = actionName.Replace("[action]", action.Name);}actionName = actionName.Split("/")[0];var route = $"/{controllerRoute}/{actionName}".Replace("//", "/");controller.Name.Replace("Controller", "");foreach (var kv in controllerRoles){if (kv.Key == controllerName){foreach (var role in kv.Value){var roleId = roles?.FirstOrDefault(x => x.RoleName == role)?.Id;var urlId = urls?.FirstOrDefault(x => x.Url == route)?.Id;bool isExist = sysRoleUrlService.IsExist(roleId, urlId);if(isExist){continue;}SysRoleUrl sysRoleUrl = new SysRoleUrl(){UrlId = urlId,RoleId = roleId,CreateUserId = "b47637e2-603f-4df0-abe9-88d70fa870ee"};sysRoleUrls.Add(sysRoleUrl);}}}}}//5. 将角色id和urlid添加到SysRoleUrl表中sysRoleUrlService.Add(sysRoleUrls);}}
}
这段代码实现了动态为系统中的角色分配 API 路径的功能。通过反射获取当前程序集的所有控制器及其方法,解析其特性并提取路径和角色信息,然后将这些信息与数据库中的已有角色和路径数据进行匹配,生成角色与路径的映射,并最终存储到数据库表中。代码的入口是静态类 AddRolePath
的 Init
方法,它接受一个 IServiceProvider
参数,用于获取依赖服务。首先,代码通过创建依赖注入的作用域,获取 ISysRoleUrlServer
、ISysUrlServer
和 ISysRoleServer
三个服务实例,分别用于管理角色与路径的关联、查询系统路径和查询角色数据。然后,代码调用相关方法查询所有路径和角色的信息,为后续操作提供基础数据。
接着,通过反射机制遍历当前程序集中的所有控制器类型,筛选出继承自 ControllerBase
的类型,并提取其 AuthorizeAttribute
特性中的 Roles
信息,记录在一个字典中,字典的键是控制器的名称(去除 “Controller” 后缀),值是控制器对应的角色列表。随后,代码进一步解析控制器中每个公开方法的路径信息,方法路径通过读取控制器和方法的 RouteAttribute
特性来拼接而成,同时会跳过带有 AllowAnonymous
特性的方法,以确保仅处理需要授权的路径。解析出的路径与控制器角色信息进行匹配,生成角色和路径的映射。
在生成角色与路径的映射关系时,代码会通过调用 sysRoleUrlService.IsExist
检查映射是否已经存在,以避免重复插入。对于不存在的映射,创建新的 SysRoleUrl
实例,设置其 RoleId
、UrlId
和 CreateUserId
属性,并将其添加到集合中。最后,调用 sysRoleUrlService.Add
方法,将所有新的映射批量写入数据库,从而完成初始化操作。这段代码的实现提供了一种动态、自动化的方式管理角色和 API 路径的关联,既减少了手动配置的繁琐,又提升了系统的灵活性和可维护性。
二、总结
本文通过 AddRolePath
类实现了动态分配角色与接口路径的功能。代码利用反射获取控制器及其方法,解析 Authorize
和 Route
特性,提取路径和角色信息,生成映射关系并存储到数据库中。此方法减少了手动配置的繁琐,提高了权限管理的自动化和灵活性,为系统提供了高效的权限初始化方案。