diff --git a/snowy-common/src/main/java/vip/xiaonuo/common/consts/CacheConstant.java b/snowy-common/src/main/java/vip/xiaonuo/common/consts/CacheConstant.java index ffcde459..4670a7e1 100644 --- a/snowy-common/src/main/java/vip/xiaonuo/common/consts/CacheConstant.java +++ b/snowy-common/src/main/java/vip/xiaonuo/common/consts/CacheConstant.java @@ -25,6 +25,11 @@ public class CacheConstant { */ public static final String PERMISSION_RESOURCE_CACHE_KEY = "permission-resource"; + /** + * 权限资源Method + */ + public static final String PERMISSION_RESOURCE_METHOD_CACHE_KEY = "permission-resource-method"; + /** * B端权限列表 */ diff --git a/snowy-common/src/main/java/vip/xiaonuo/common/detector/EnvironmentDetector.java b/snowy-common/src/main/java/vip/xiaonuo/common/detector/EnvironmentDetector.java new file mode 100644 index 00000000..c861eb51 --- /dev/null +++ b/snowy-common/src/main/java/vip/xiaonuo/common/detector/EnvironmentDetector.java @@ -0,0 +1,72 @@ +/* + * Copyright [2022] [https://www.xiaonuo.vip] + * + * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点: + * + * 1.请不要删除和修改根目录下的LICENSE文件。 + * 2.请不要删除和修改Snowy源码头部的版权声明。 + * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。 + * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip + * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。 + * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip + */ +package vip.xiaonuo.common.detector; + +import cn.hutool.core.util.ObjectUtil; +import jakarta.annotation.Nullable; +import jakarta.annotation.Resource; +import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.ApplicationListener; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; +import vip.xiaonuo.common.prop.CommonProperties; + +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; + +/** + * 环境检测器 + * + * @author jiangcs + * @since 2025/9/13 23:20 + */ +@Configuration +public class EnvironmentDetector implements ApplicationListener { + + // 是否是SnowyCloud + private static boolean snowyCloud = false; + + @Resource + private Environment environment; + @Resource + private CommonProperties commonProperties; + + @Override + public void onApplicationEvent(@Nullable ApplicationReadyEvent event) { + // 检查是否存在 Nacos 相关配置 + boolean hasNacosConfig = environment.containsProperty("spring.cloud.nacos.config.server-addr"); + boolean hasNacosDiscovery = environment.containsProperty("spring.cloud.nacos.discovery.server-addr"); + snowyCloud = hasNacosConfig || hasNacosDiscovery; + } + + /** + * 转换后端路径 + * + * @param path 路径 + * @return 路径 + */ + public String convertBackendPath(String path) { + if (snowyCloud) { + List> list = commonProperties.getBackendPaths(); + Set> urlSet = list.stream().filter(m -> path.startsWith(m.get("name"))) + .collect(Collectors.toSet()); + if (ObjectUtil.isNotEmpty(urlSet)) { + return urlSet.iterator().next().get("value") + path; + } + } + return path; + } + +} diff --git a/snowy-common/src/main/java/vip/xiaonuo/common/prop/CommonProperties.java b/snowy-common/src/main/java/vip/xiaonuo/common/prop/CommonProperties.java index a54b2b29..ff9dbce6 100644 --- a/snowy-common/src/main/java/vip/xiaonuo/common/prop/CommonProperties.java +++ b/snowy-common/src/main/java/vip/xiaonuo/common/prop/CommonProperties.java @@ -17,6 +17,9 @@ import lombok.Setter; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; +import java.util.List; +import java.util.Map; + /** * 通用基础配置 * @@ -32,6 +35,14 @@ public class CommonProperties { /** 前端地址 */ private String frontUrl; - /** 后端地址 */ + /** + * 后端地址 + */ private String backendUrl; + + /** + * 后端路由 + */ + private List> backendPaths; + } diff --git a/snowy-common/src/main/java/vip/xiaonuo/common/prop/DomProperties.java b/snowy-common/src/main/java/vip/xiaonuo/common/prop/DomProperties.java new file mode 100644 index 00000000..d6002d97 --- /dev/null +++ b/snowy-common/src/main/java/vip/xiaonuo/common/prop/DomProperties.java @@ -0,0 +1,37 @@ +/* + * Copyright [2022] [https://www.xiaonuo.vip] + * + * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点: + * + * 1.请不要删除和修改根目录下的LICENSE文件。 + * 2.请不要删除和修改Snowy源码头部的版权声明。 + * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。 + * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip + * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。 + * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip + */ +package vip.xiaonuo.common.prop; + +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.stereotype.Component; + +/** + * 数据建模相关配置 + * + * @author xuyuxiang + * @date 2022/1/2 17:03 + */ +@Getter +@Setter +@Component +@ConfigurationProperties(prefix = "snowy.config.dom") +public class DomProperties { + + /** + * 数据建模,授权数据库表前缀,逗号分割 + */ + private String authTableNamePrefixes; + +} diff --git a/snowy-plugin/snowy-plugin-sys/src/main/java/vip/xiaonuo/sys/modular/role/service/impl/SysRoleServiceImpl.java b/snowy-plugin/snowy-plugin-sys/src/main/java/vip/xiaonuo/sys/modular/role/service/impl/SysRoleServiceImpl.java index 7c1b0dd4..6a07f820 100644 --- a/snowy-plugin/snowy-plugin-sys/src/main/java/vip/xiaonuo/sys/modular/role/service/impl/SysRoleServiceImpl.java +++ b/snowy-plugin/snowy-plugin-sys/src/main/java/vip/xiaonuo/sys/modular/role/service/impl/SysRoleServiceImpl.java @@ -12,16 +12,15 @@ */ package vip.xiaonuo.sys.modular.role.service.impl; -import cn.dev33.satoken.annotation.SaCheckPermission; import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollStreamUtil; import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.convert.Convert; import cn.hutool.core.lang.tree.Tree; import cn.hutool.core.lang.tree.TreeNode; import cn.hutool.core.lang.tree.TreeUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; -import cn.hutool.extra.spring.SpringUtil; import cn.hutool.json.JSONObject; import cn.hutool.json.JSONUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; @@ -29,12 +28,11 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import io.swagger.v3.oas.annotations.Operation; import jakarta.annotation.Resource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import org.springframework.web.servlet.mvc.condition.PathPatternsRequestCondition; -import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; +import vip.xiaonuo.common.cache.CommonCacheOperator; +import vip.xiaonuo.common.consts.CacheConstant; import vip.xiaonuo.common.enums.CommonSortOrderEnum; import vip.xiaonuo.common.exception.CommonException; import vip.xiaonuo.common.listener.CommonDataChangeEventCenter; @@ -63,10 +61,7 @@ import vip.xiaonuo.sys.modular.user.entity.SysUser; import vip.xiaonuo.sys.modular.user.enums.SysUserStatusEnum; import vip.xiaonuo.sys.modular.user.service.SysUserService; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.util.*; import java.util.stream.Collectors; /** @@ -96,22 +91,25 @@ public class SysRoleServiceImpl extends ServiceImpl impl @Resource private MobileMenuApi mobileMenuApi; + @Resource + private CommonCacheOperator commonCacheOperator; + @Override public Page page(SysRolePageParam sysRolePageParam) { QueryWrapper queryWrapper = new QueryWrapper().checkSqlInjection(); // 查询部分字段 queryWrapper.lambda().select(SysRole::getId, SysRole::getOrgId, SysRole::getName, SysRole::getCode, SysRole::getCategory, SysRole::getSortCode); - if(ObjectUtil.isNotEmpty(sysRolePageParam.getOrgId())) { + if (ObjectUtil.isNotEmpty(sysRolePageParam.getOrgId())) { queryWrapper.lambda().eq(SysRole::getOrgId, sysRolePageParam.getOrgId()); } - if(ObjectUtil.isNotEmpty(sysRolePageParam.getCategory())) { + if (ObjectUtil.isNotEmpty(sysRolePageParam.getCategory())) { queryWrapper.lambda().eq(SysRole::getCategory, sysRolePageParam.getCategory()); } - if(ObjectUtil.isNotEmpty(sysRolePageParam.getSearchKey())) { + if (ObjectUtil.isNotEmpty(sysRolePageParam.getSearchKey())) { queryWrapper.lambda().like(SysRole::getName, sysRolePageParam.getSearchKey()); } - if(ObjectUtil.isAllNotEmpty(sysRolePageParam.getSortField(), sysRolePageParam.getSortOrder())) { + if (ObjectUtil.isAllNotEmpty(sysRolePageParam.getSortField(), sysRolePageParam.getSortOrder())) { CommonSortOrderEnum.validate(sysRolePageParam.getSortOrder()); queryWrapper.orderBy(true, sysRolePageParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()), StrUtil.toUnderlineCase(sysRolePageParam.getSortField())); @@ -134,8 +132,8 @@ public class SysRoleServiceImpl extends ServiceImpl impl private void checkParam(SysRoleAddParam sysRoleAddParam) { SysRoleCategoryEnum.validate(sysRoleAddParam.getCategory()); - if(SysRoleCategoryEnum.ORG.getValue().equals(sysRoleAddParam.getCategory())) { - if(ObjectUtil.isEmpty(sysRoleAddParam.getOrgId())) { + if (SysRoleCategoryEnum.ORG.getValue().equals(sysRoleAddParam.getCategory())) { + if (ObjectUtil.isEmpty(sysRoleAddParam.getOrgId())) { throw new CommonException("orgId不能为空"); } } else { @@ -143,8 +141,8 @@ public class SysRoleServiceImpl extends ServiceImpl impl } boolean repeatName = this.count(new LambdaQueryWrapper().eq(SysRole::getOrgId, sysRoleAddParam.getOrgId()) .eq(SysRole::getName, sysRoleAddParam.getName())) > 0; - if(repeatName) { - if(ObjectUtil.isEmpty(sysRoleAddParam.getOrgId())) { + if (repeatName) { + if (ObjectUtil.isEmpty(sysRoleAddParam.getOrgId())) { throw new CommonException("存在重复的全局角色,名称为:{}", sysRoleAddParam.getName()); } else { throw new CommonException("同组织下存在重复的角色,名称为:{}", sysRoleAddParam.getName()); @@ -152,8 +150,8 @@ public class SysRoleServiceImpl extends ServiceImpl impl } boolean repeatCode = this.count(new LambdaQueryWrapper().eq(SysRole::getOrgId, sysRoleAddParam.getOrgId()) .eq(SysRole::getCode, sysRoleAddParam.getCode())) > 0; - if(repeatCode) { - if(ObjectUtil.isEmpty(sysRoleAddParam.getOrgId())) { + if (repeatCode) { + if (ObjectUtil.isEmpty(sysRoleAddParam.getOrgId())) { throw new CommonException("存在重复的全局角色,编码为:{}", sysRoleAddParam.getCode()); } else { throw new CommonException("同组织下存在重复的角色,编码为:{}", sysRoleAddParam.getCode()); @@ -167,7 +165,7 @@ public class SysRoleServiceImpl extends ServiceImpl impl SysRole sysRole = this.queryEntity(sysRoleEditParam.getId()); checkParam(sysRoleEditParam); boolean superRole = sysRole.getCode().equals(SysBuildInEnum.BUILD_IN_ROLE_CODE.getValue()); - if(superRole) { + if (superRole) { throw new CommonException("不可编辑超管角色"); } BeanUtil.copyProperties(sysRoleEditParam, sysRole); @@ -179,8 +177,8 @@ public class SysRoleServiceImpl extends ServiceImpl impl private void checkParam(SysRoleEditParam sysRoleEditParam) { SysRoleCategoryEnum.validate(sysRoleEditParam.getCategory()); - if(SysRoleCategoryEnum.ORG.getValue().equals(sysRoleEditParam.getCategory())) { - if(ObjectUtil.isEmpty(sysRoleEditParam.getOrgId())) { + if (SysRoleCategoryEnum.ORG.getValue().equals(sysRoleEditParam.getCategory())) { + if (ObjectUtil.isEmpty(sysRoleEditParam.getOrgId())) { throw new CommonException("orgId不能为空"); } } else { @@ -188,8 +186,8 @@ public class SysRoleServiceImpl extends ServiceImpl impl } boolean repeatName = this.count(new LambdaQueryWrapper().eq(SysRole::getOrgId, sysRoleEditParam.getOrgId()) .eq(SysRole::getName, sysRoleEditParam.getName()).ne(SysRole::getId, sysRoleEditParam.getId())) > 0; - if(repeatName) { - if(ObjectUtil.isEmpty(sysRoleEditParam.getOrgId())) { + if (repeatName) { + if (ObjectUtil.isEmpty(sysRoleEditParam.getOrgId())) { throw new CommonException("存在重复的全局角色,名称为:{}", sysRoleEditParam.getName()); } else { throw new CommonException("同组织下存在重复的角色,名称为:{}", sysRoleEditParam.getName()); @@ -197,8 +195,8 @@ public class SysRoleServiceImpl extends ServiceImpl impl } boolean repeatCode = this.count(new LambdaQueryWrapper().eq(SysRole::getOrgId, sysRoleEditParam.getOrgId()) .eq(SysRole::getCode, sysRoleEditParam.getCode()).ne(SysRole::getId, sysRoleEditParam.getId())) > 0; - if(repeatCode) { - if(ObjectUtil.isEmpty(sysRoleEditParam.getOrgId())) { + if (repeatCode) { + if (ObjectUtil.isEmpty(sysRoleEditParam.getOrgId())) { throw new CommonException("存在重复的全局角色,编码为:{}", sysRoleEditParam.getCode()); } else { throw new CommonException("同组织下存在重复的角色,编码为:{}", sysRoleEditParam.getCode()); @@ -211,10 +209,10 @@ public class SysRoleServiceImpl extends ServiceImpl impl @Override public void delete(List sysRoleIdParamList) { List sysRoleIdList = CollStreamUtil.toList(sysRoleIdParamList, SysRoleIdParam::getId); - if(ObjectUtil.isNotEmpty(sysRoleIdList)) { + if (ObjectUtil.isNotEmpty(sysRoleIdList)) { boolean containsSuperAdminRole = this.listByIds(sysRoleIdList).stream().map(SysRole::getCode) .collect(Collectors.toSet()).contains(SysBuildInEnum.BUILD_IN_ROLE_CODE.getValue()); - if(containsSuperAdminRole) { + if (containsSuperAdminRole) { throw new CommonException("不可删除系统内置超管角色"); } // 级联删除角色与用户关系 @@ -258,12 +256,12 @@ public class SysRoleServiceImpl extends ServiceImpl impl SysRole sysRole = this.queryEntity(id); List menuIdList = sysRoleGrantResourceParam.getGrantInfoList().stream() .map(SysRoleGrantResourceParam.SysRoleGrantResource::getMenuId).collect(Collectors.toList()); - if(!SysBuildInEnum.BUILD_IN_ROLE_CODE.getValue().equals(sysRole.getCode())) { - if(ObjectUtil.isNotEmpty(menuIdList)) { + if (!SysBuildInEnum.BUILD_IN_ROLE_CODE.getValue().equals(sysRole.getCode())) { + if (ObjectUtil.isNotEmpty(menuIdList)) { Set sysModuleIdList = sysMenuService.listByIds(menuIdList).stream().map(SysMenu::getModule).collect(Collectors.toSet()); boolean containsSystemModule = sysModuleService.listByIds(sysModuleIdList).stream().map(SysModule::getCode) .collect(Collectors.toSet()).contains(SysBuildInEnum.BUILD_IN_MODULE_CODE.getValue()); - if(containsSystemModule) { + if (containsSystemModule) { throw new CommonException("非超管角色不可被授权系统模块菜单资源"); } } @@ -326,7 +324,7 @@ public class SysRoleServiceImpl extends ServiceImpl impl public void grantUser(SysRoleGrantUserParam sysRoleGrantUserParam) { String id = sysRoleGrantUserParam.getId(); List grantInfoList = sysRoleGrantUserParam.getGrantInfoList(); - if(sysRoleGrantUserParam.getRemoveFirst()) { + if (sysRoleGrantUserParam.getRemoveFirst()) { sysRelationService.remove(new LambdaQueryWrapper().eq(SysRelation::getTargetId, id) .eq(SysRelation::getCategory, SysRelationCategoryEnum.SYS_USER_HAS_ROLE.getValue())); } @@ -342,7 +340,7 @@ public class SysRoleServiceImpl extends ServiceImpl impl @Override public SysRole queryEntity(String id) { SysRole sysRole = this.getById(id); - if(ObjectUtil.isEmpty(sysRole)) { + if (ObjectUtil.isEmpty(sysRole)) { throw new CommonException("角色不存在,id值为:{}", id); } return sysRole; @@ -354,7 +352,7 @@ public class SysRoleServiceImpl extends ServiceImpl impl public List> orgTreeSelector() { List sysOrgList = sysOrgService.getAllOrgList(); List> treeNodeList = sysOrgList.stream().map(sysOrg -> - new TreeNode<>(sysOrg.getId(), sysOrg.getParentId(), sysOrg.getName(), sysOrg.getSortCode())) + new TreeNode<>(sysOrg.getId(), sysOrg.getParentId(), sysOrg.getName(), sysOrg.getSortCode())) .collect(Collectors.toList()); return TreeUtil.build(treeNodeList, "0"); } @@ -364,7 +362,7 @@ public class SysRoleServiceImpl extends ServiceImpl impl LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>(); lambdaQueryWrapper.in(SysMenu::getCategory, SysResourceCategoryEnum.MODULE.getValue(), SysResourceCategoryEnum.MENU.getValue(), SysResourceCategoryEnum.BUTTON.getValue()); - if(!containsTen) { + if (!containsTen) { lambdaQueryWrapper.ne(SysMenu::getCode, SysBuildInEnum.BUILD_IN_NO_TEN_MENU_CODE.getValue()); } return this.resourceTreeSelector(sysMenuService.list(lambdaQueryWrapper)); @@ -401,18 +399,18 @@ public class SysRoleServiceImpl extends ServiceImpl impl // 排除菜单中的目录 boolean isLeafMenu = !"0".equals(sysMenu.getId()) && !sysMenu.getMenuType().equals(SysResourceMenuTypeEnum.CATALOG.getValue()); - if(isLeafMenu) { + if (isLeafMenu) { SysRoleGrantResourceTreeResult.SysRoleGrantResourceMenuResult sysRoleGrantResourceMenuResult = new SysRoleGrantResourceTreeResult.SysRoleGrantResourceMenuResult(); BeanUtil.copyProperties(sysMenu, sysRoleGrantResourceMenuResult); JSONObject parentJsonObject = getParentNode(treeList, sysMenu); List parentIdSplitList = StrUtil.split(parentJsonObject.getStr("parentId"), StrUtil.DASHED); List parentNameSplitList = StrUtil.split(parentJsonObject.getStr("parentName"), StrUtil.DASHED); - if(parentNameSplitList.size() > 1) { + if (parentNameSplitList.size() > 1) { sysRoleGrantResourceMenuResult.setParentId(parentIdSplitList.get(3)); sysRoleGrantResourceMenuResult.setParentName(parentNameSplitList.get(0)); StringBuilder selfNamePrefix = new StringBuilder(); - for(int i = 1; i< parentNameSplitList.size(); i++) { + for (int i = 1; i < parentNameSplitList.size(); i++) { selfNamePrefix.append(parentNameSplitList.get(i)).append(StrUtil.DASHED); } sysRoleGrantResourceMenuResult.setTitle(selfNamePrefix + sysRoleGrantResourceMenuResult.getTitle()); @@ -455,26 +453,12 @@ public class SysRoleServiceImpl extends ServiceImpl impl @Override public List permissionTreeSelector() { List permissionResult = CollectionUtil.newArrayList(); - SpringUtil.getApplicationContext().getBeansOfType(RequestMappingHandlerMapping.class).values() - .forEach(requestMappingHandlerMapping -> requestMappingHandlerMapping.getHandlerMethods() - .forEach((key, value) -> { - SaCheckPermission saCheckPermission = value.getMethod().getAnnotation(SaCheckPermission.class); - if(ObjectUtil.isNotEmpty(saCheckPermission)) { - PathPatternsRequestCondition pathPatternsCondition = key.getPathPatternsCondition(); - if (pathPatternsCondition != null) { - String apiName = "未定义接口名称"; - Operation apiOperation = value.getMethod().getAnnotation(Operation.class); - if(ObjectUtil.isNotEmpty(apiOperation)) { - String annotationValue = apiOperation.summary(); - if(ObjectUtil.isNotEmpty(annotationValue)) { - apiName = annotationValue; - } - } - String nm = StrUtil.BRACKET_START + apiName + StrUtil.BRACKET_END; - pathPatternsCondition.getPatterns().forEach(pt -> permissionResult.add(pt + nm)); - } - } - })); + + Object permissionResourceObject = commonCacheOperator.get(CacheConstant.PERMISSION_RESOURCE_CACHE_KEY); + if (Objects.nonNull(permissionResourceObject)) { + permissionResult = Convert.toList(String.class, permissionResourceObject); + } + return CollectionUtil.sortByPinyin(permissionResult.stream().filter(api -> !api.startsWith("/" + StrUtil.BRACKET_START) && !api.startsWith("/error") @@ -488,20 +472,20 @@ public class SysRoleServiceImpl extends ServiceImpl impl // 查询部分字段 queryWrapper.lambda().select(SysRole::getId, SysRole::getOrgId, SysRole::getName, SysRole::getCode, SysRole::getCategory, SysRole::getSortCode); - if(ObjectUtil.isNotEmpty(sysRoleSelectorRoleParam.getOrgId())) { + if (ObjectUtil.isNotEmpty(sysRoleSelectorRoleParam.getOrgId())) { queryWrapper.lambda().eq(SysRole::getOrgId, sysRoleSelectorRoleParam.getOrgId()); } - if(ObjectUtil.isNotEmpty(sysRoleSelectorRoleParam.getCategory())) { + if (ObjectUtil.isNotEmpty(sysRoleSelectorRoleParam.getCategory())) { queryWrapper.lambda().eq(SysRole::getCategory, sysRoleSelectorRoleParam.getCategory()); } - if(ObjectUtil.isNotEmpty(sysRoleSelectorRoleParam.getSearchKey())) { + if (ObjectUtil.isNotEmpty(sysRoleSelectorRoleParam.getSearchKey())) { queryWrapper.lambda().like(SysRole::getName, sysRoleSelectorRoleParam.getSearchKey()); } - if(ObjectUtil.isNotEmpty(sysRoleSelectorRoleParam.getDataScopeList())) { + if (ObjectUtil.isNotEmpty(sysRoleSelectorRoleParam.getDataScopeList())) { queryWrapper.lambda().in(SysRole::getOrgId, sysRoleSelectorRoleParam.getDataScopeList()); } // 排除超管角色 - if(sysRoleSelectorRoleParam.isExcludeSuperAdmin()) { + if (sysRoleSelectorRoleParam.isExcludeSuperAdmin()) { queryWrapper.lambda().ne(SysRole::getCode, SysBuildInEnum.BUILD_IN_ROLE_CODE.getValue()); } queryWrapper.lambda().orderByAsc(SysRole::getSortCode); @@ -517,7 +501,7 @@ public class SysRoleServiceImpl extends ServiceImpl impl queryWrapper.lambda().select(SysUser::getId, SysUser::getAvatar, SysUser::getOrgId, SysUser::getPositionId, SysUser::getAccount, SysUser::getName, SysUser::getSortCode, SysUser::getGender, SysUser::getEntryDate); // 如果查询条件为空,则直接查询 - if(ObjectUtil.isAllEmpty(sysRoleSelectorUserParam.getOrgId(), sysRoleSelectorUserParam.getSearchKey())) { + if (ObjectUtil.isAllEmpty(sysRoleSelectorUserParam.getOrgId(), sysRoleSelectorUserParam.getSearchKey())) { return sysUserService.getAllUserSelectorList(); } else { if (ObjectUtil.isNotEmpty(sysRoleSelectorUserParam.getOrgId())) { @@ -544,9 +528,9 @@ public class SysRoleServiceImpl extends ServiceImpl impl List> resultList = CollectionUtil.newArrayList(); getNode(treeList, sysMenu.getId(), resultList); JSONObject jsonObject = JSONUtil.createObj(); - if(ObjectUtil.isNotEmpty(resultList)) { + if (ObjectUtil.isNotEmpty(resultList)) { Tree currentNode = resultList.get(0); - if("0".equals(currentNode.getId()) || "0".equals(currentNode.getParentId())) { + if ("0".equals(currentNode.getId()) || "0".equals(currentNode.getParentId())) { jsonObject.set("parentId", sysMenu.getId()); jsonObject.set("parentName", sysMenu.getTitle()); } else { @@ -581,13 +565,13 @@ public class SysRoleServiceImpl extends ServiceImpl impl } public void getNode(List> treeList, String id, List> resultList) { - for (Tree tree: treeList) { - if(tree.getId().equals(id)) { + for (Tree tree : treeList) { + if (tree.getId().equals(id)) { resultList.add(tree); break; } else { List> children = tree.getChildren(); - if(ObjectUtil.isNotEmpty(children)) { + if (ObjectUtil.isNotEmpty(children)) { getNode(children, id, resultList); } } @@ -597,9 +581,9 @@ public class SysRoleServiceImpl extends ServiceImpl impl public List getChildListById(List originDataList, String id, boolean includeSelf) { List sysResourceList = CollectionUtil.newArrayList(); execRecursionFindChild(originDataList, id, sysResourceList); - if(includeSelf) { + if (includeSelf) { SysMenu self = this.getById(originDataList, id); - if(ObjectUtil.isNotEmpty(self)) { + if (ObjectUtil.isNotEmpty(self)) { sysResourceList.add(self); } } @@ -609,9 +593,9 @@ public class SysRoleServiceImpl extends ServiceImpl impl public List getParentListById(List originDataList, String id, boolean includeSelf) { List sysResourceList = CollectionUtil.newArrayList(); execRecursionFindParent(originDataList, id, sysResourceList); - if(includeSelf) { + if (includeSelf) { SysMenu self = this.getById(originDataList, id); - if(ObjectUtil.isNotEmpty(self)) { + if (ObjectUtil.isNotEmpty(self)) { sysResourceList.add(self); } } @@ -620,7 +604,7 @@ public class SysRoleServiceImpl extends ServiceImpl impl public void execRecursionFindChild(List originDataList, String id, List resultList) { originDataList.forEach(item -> { - if(item.getParentId().equals(id)) { + if (item.getParentId().equals(id)) { resultList.add(item); execRecursionFindChild(originDataList, item.getId(), resultList); } @@ -629,9 +613,9 @@ public class SysRoleServiceImpl extends ServiceImpl impl public void execRecursionFindParent(List originDataList, String id, List resultList) { originDataList.forEach(item -> { - if(item.getId().equals(id)) { + if (item.getId().equals(id)) { SysMenu parent = this.getById(originDataList, item.getParentId()); - if(ObjectUtil.isNotEmpty(parent)) { + if (ObjectUtil.isNotEmpty(parent)) { resultList.add(parent); } execRecursionFindParent(originDataList, item.getParentId(), resultList); @@ -641,16 +625,16 @@ public class SysRoleServiceImpl extends ServiceImpl impl public SysMenu getById(List originDataList, String id) { int index = CollStreamUtil.toList(originDataList, SysMenu::getId).indexOf(id); - return index == -1?null:originDataList.get(index); + return index == -1 ? null : originDataList.get(index); } public SysMenu getParentById(List originDataList, String id) { SysMenu self = this.getById(originDataList, id); - return ObjectUtil.isNotEmpty(self)?self:this.getById(originDataList, self.getParentId()); + return ObjectUtil.isNotEmpty(self) ? self : this.getById(originDataList, self.getParentId()); } public SysMenu getChildById(List originDataList, String id) { int index = CollStreamUtil.toList(originDataList, SysMenu::getParentId).indexOf(id); - return index == -1?null:originDataList.get(index); + return index == -1 ? null : originDataList.get(index); } } diff --git a/snowy-web-app/src/main/java/vip/xiaonuo/core/config/GlobalConfigure.java b/snowy-web-app/src/main/java/vip/xiaonuo/core/config/GlobalConfigure.java index fe583351..51bdd284 100644 --- a/snowy-web-app/src/main/java/vip/xiaonuo/core/config/GlobalConfigure.java +++ b/snowy-web-app/src/main/java/vip/xiaonuo/core/config/GlobalConfigure.java @@ -177,8 +177,8 @@ public class GlobalConfigure implements WebMvcConfigurer { /* 可视化大屏插件放行 */ "/screen/project/releaseDetail", "/screen/project/verifyAccessPassword", - "/dbs/application/getAuth", - "/dbs/dataSet/invoke", + "/dataset/application/getAuth", + "/dataset/dataSet/invoke", /* 知识库插件放行 */ "/wiki/wikidocumentshare/getInfoByCode", diff --git a/snowy-web-app/src/main/java/vip/xiaonuo/core/listener/ResourceCollectListener.java b/snowy-web-app/src/main/java/vip/xiaonuo/core/listener/ResourceCollectListener.java new file mode 100644 index 00000000..e38d13d8 --- /dev/null +++ b/snowy-web-app/src/main/java/vip/xiaonuo/core/listener/ResourceCollectListener.java @@ -0,0 +1,170 @@ +/* + * Copyright [2022] [https://www.xiaonuo.vip] + * + * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点: + * + * 1.请不要删除和修改根目录下的LICENSE文件。 + * 2.请不要删除和修改Snowy源码头部的版权声明。 + * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。 + * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip + * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。 + * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip + */ +package vip.xiaonuo.core.listener; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.collection.CollectionUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.extra.spring.SpringUtil; +import cn.hutool.log.Log; +import io.swagger.v3.oas.annotations.Operation; +import jakarta.annotation.Resource; +import org.springframework.boot.CommandLineRunner; +import org.springframework.core.annotation.Order; +import org.springframework.http.HttpMethod; +import org.springframework.stereotype.Component; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.mvc.condition.PathPatternsRequestCondition; +import org.springframework.web.servlet.mvc.condition.PatternsRequestCondition; +import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; +import vip.xiaonuo.common.cache.CommonCacheOperator; +import vip.xiaonuo.common.consts.CacheConstant; + +import java.util.List; +import java.util.Map; +import java.util.Objects; + +/** + * 资源搜集器,将项目中所有接口(带@RequestMapping的)都搜集起来 + *

+ * 搜集到的接口会被缓存 + * + * @author dongxiayu + * @date 2023/1/29 23:24 + **/ +@Component +@Order(1) +public class ResourceCollectListener implements CommandLineRunner { + + private static final Log log = Log.get(); + + @Resource + private CommonCacheOperator commonCacheOperator; + + @Override + public void run(String... args) { + //1.获取所有后端接口 + List permissionResult = CollectionUtil.newArrayList(); + Map permissionMethodMap = MapUtil.newHashMap(); + SpringUtil.getApplicationContext().getBeansOfType(RequestMappingHandlerMapping.class).values() + .forEach(requestMappingHandlerMapping -> requestMappingHandlerMapping.getHandlerMethods() + .forEach((key, value) -> { + SaCheckPermission saCheckPermission = value.getMethod().getAnnotation(SaCheckPermission.class); + if (ObjectUtil.isNotEmpty(saCheckPermission)) { + String path = null; + // Spring Boot 3.x + PathPatternsRequestCondition pathPatternsCondition = key.getPathPatternsCondition(); + if (pathPatternsCondition != null) { + path = pathPatternsCondition.getPatterns().iterator().next().getPatternString(); + } + // Spring Boot 2.x + PatternsRequestCondition patternsCondition = key.getPatternsCondition(); + if (patternsCondition != null) { + path = patternsCondition.getPatterns().iterator().next(); + } + if (path != null) { + String apiName = "未定义接口名称"; + Operation apiOperation = value.getMethod().getAnnotation(Operation.class); + if (ObjectUtil.isNotEmpty(apiOperation)) { + String annotationValue = apiOperation.summary(); + if (ObjectUtil.isNotEmpty(annotationValue)) { + apiName = annotationValue; + } + } + + String permissionKey = path + StrUtil.BRACKET_START + apiName + StrUtil.BRACKET_END; + permissionResult.add(permissionKey); + + // build permission method map data + buildPermissionMethodMapData(value, permissionMethodMap, permissionKey); + } + } + })); + + //2.汇总添加到缓存 + Object permissionResourceObject = commonCacheOperator.get(CacheConstant.PERMISSION_RESOURCE_CACHE_KEY); + List permissionResource; + if (Objects.isNull(permissionResourceObject)) { + permissionResource = CollUtil.newArrayList(); + } else { + permissionResource = Convert.toList(String.class, permissionResourceObject); + } + if (CollUtil.isNotEmpty(permissionResult)) { + for (String permission : permissionResult) { + if (!permissionResource.contains(permission)) { + permissionResource.add(permission); + } + } + + // 刷新缓存 + commonCacheOperator.put(CacheConstant.PERMISSION_RESOURCE_CACHE_KEY, permissionResource); + } + + // 3.汇总添加Permission Method Map数据到缓存 + refreshPermissionMethodMapDataToCache(permissionMethodMap); + + log.info(">>> 缓存资源URL集合完成!资源数量:{}", permissionResult.size()); + } + + /** + * refreshPermissionMethodMapDataToCache + * + * @param permissionMethodMap map of key {@link String},value {@link String} + */ + private void refreshPermissionMethodMapDataToCache(Map permissionMethodMap) { + Object permissionMethodMapObject = commonCacheOperator.get(CacheConstant.PERMISSION_RESOURCE_METHOD_CACHE_KEY); + Map permissionMethodMapFromCache = null; + if (Objects.isNull(permissionMethodMapObject)) { + permissionMethodMapFromCache = MapUtil.newHashMap(); + } else { + permissionMethodMapFromCache = Convert.toMap(String.class, String.class, permissionMethodMapObject); + } + if (CollUtil.isNotEmpty(permissionMethodMap)) { + for (Map.Entry permissionMethodEntry : permissionMethodMap.entrySet()) { + String permissionKey = permissionMethodEntry.getKey(); + String permissionMethod = permissionMethodEntry.getValue(); + permissionMethodMapFromCache.put(permissionKey, permissionMethod); + } + + // 刷新缓存 + commonCacheOperator.put(CacheConstant.PERMISSION_RESOURCE_METHOD_CACHE_KEY, permissionMethodMapFromCache); + } + } + + /** + * buildPermissionMethodMapData + * + * @param value {@link HandlerMethod} + * @param permissionMethodMap map of key {@link String},value {@link String} + * @param permissionKey {@link String} + */ + private static void buildPermissionMethodMapData(HandlerMethod value, Map permissionMethodMap, String permissionKey) { + GetMapping getMappingAnno = value.getMethod().getAnnotation(GetMapping.class); + PostMapping postMappingAnno = value.getMethod().getAnnotation(PostMapping.class); + + String permissionMethod = null; + if (Objects.nonNull(getMappingAnno)) { + permissionMethod = HttpMethod.GET.name(); + } + if (Objects.nonNull(postMappingAnno)) { + permissionMethod = HttpMethod.POST.name(); + } + permissionMethodMap.put(permissionKey, permissionMethod); + } +}