From eadb7f76334d39b7d2c7058f999e8a7dca866534 Mon Sep 17 00:00:00 2001 From: gaoqr <13665037151@163.com> Date: Tue, 29 Oct 2024 16:17:25 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E7=BB=84=E7=BB=87=E5=A5=97=E9=A4=90?= =?UTF-8?q?=E4=B8=8B=E7=9A=84=E6=9D=83=E9=99=90=E8=8F=9C=E5=8D=95id?= =?UTF-8?q?=E6=94=AF=E6=8C=81=E7=BC=93=E5=AD=98=E3=80=81=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E5=A5=97=E9=A4=90=E5=86=85=E5=AE=B9=E6=88=96=E7=BB=84=E7=BB=87?= =?UTF-8?q?=E6=9B=B4=E6=8D=A2=E5=A5=97=E9=A4=90=E6=97=B6=E5=88=B7=E6=96=B0?= =?UTF-8?q?=E5=AF=B9=E5=BA=94=E7=BC=93=E5=AD=98=EF=BC=9B2=E3=80=81?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E7=BB=84=E7=BB=87=E5=A5=97=E9=A4=90=E4=B8=8B?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E7=9A=84=E8=BF=87=E6=BB=A4=EF=BC=9A=E7=99=BB?= =?UTF-8?q?=E5=BD=95=E7=B3=BB=E7=BB=9F=E5=B1=95=E7=8E=B0=E8=8F=9C=E5=8D=95?= =?UTF-8?q?=E3=80=81=E6=8E=A5=E5=8F=A3=E6=9D=83=E9=99=90=E4=B8=B2=E6=A0=A1?= =?UTF-8?q?=E9=AA=8C=E3=80=81=E8=A7=92=E8=89=B2=E7=AE=A1=E7=90=86=E7=BB=99?= =?UTF-8?q?=E8=A7=92=E8=89=B2=E6=8E=88=E6=9D=83=E7=9A=84=E5=8F=AF=E9=80=89?= =?UTF-8?q?=E8=8F=9C=E5=8D=95=E5=88=97=E8=A1=A8=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/redis/OrganRedisCacheManager.java | 18 +++- .../redis/core/TimeoutRedisCacheManager.java | 9 +- .../system/enums/ErrorCodeConstants.java | 2 + .../controller/admin/auth/AuthController.java | 15 ++- .../admin/permission/MenuController.java | 21 ++-- .../permission/PermissionController.java | 7 +- .../system/dal/redis/RedisKeyConstants.java | 8 +- .../SystemPermissionRefreshRedisListener.java | 3 + .../system/service/organ/OrganService.java | 2 +- .../service/organ/OrganServiceImpl.java | 8 +- .../service/organ/TenantPackageService.java | 8 ++ .../organ/TenantPackageServiceImpl.java | 25 ++++- .../service/permission/PermissionService.java | 16 ++- .../permission/PermissionServiceImpl.java | 100 ++++++++++++++---- .../system/service/user/AdminUserService.java | 8 ++ .../service/user/AdminUserServiceImpl.java | 7 ++ 16 files changed, 216 insertions(+), 41 deletions(-) diff --git a/cf-framework/cf-spring-boot-starter-biz-organ/src/main/java/com/cf/imes/framework/organ/core/redis/OrganRedisCacheManager.java b/cf-framework/cf-spring-boot-starter-biz-organ/src/main/java/com/cf/imes/framework/organ/core/redis/OrganRedisCacheManager.java index 5cc2d3ea7..3990692e7 100644 --- a/cf-framework/cf-spring-boot-starter-biz-organ/src/main/java/com/cf/imes/framework/organ/core/redis/OrganRedisCacheManager.java +++ b/cf-framework/cf-spring-boot-starter-biz-organ/src/main/java/com/cf/imes/framework/organ/core/redis/OrganRedisCacheManager.java @@ -1,5 +1,6 @@ package com.cf.imes.framework.organ.core.redis; +import cn.hutool.core.text.CharSequenceUtil; import com.cf.imes.framework.redis.core.TimeoutRedisCacheManager; import com.cf.imes.framework.organ.core.context.OrganContextHolder; import lombok.extern.slf4j.Slf4j; @@ -8,6 +9,9 @@ import org.springframework.data.redis.cache.RedisCacheConfiguration; import org.springframework.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.cache.RedisCacheWriter; +import java.util.ArrayList; +import java.util.List; + /** * 多组织的 {@link RedisCacheManager} 实现类 * @@ -18,6 +22,13 @@ import org.springframework.data.redis.cache.RedisCacheWriter; @Slf4j public class OrganRedisCacheManager extends TimeoutRedisCacheManager { + // 不需要拼接组织id的redis-key列表 + private static final List ignoreOrganIdKeyList = new ArrayList<>(); + + static { + ignoreOrganIdKeyList.add("tenant_package_menu_ids"); + } + public OrganRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) { super(cacheWriter, defaultCacheConfiguration); @@ -25,9 +36,14 @@ public class OrganRedisCacheManager extends TimeoutRedisCacheManager { @Override public Cache getCache(String name) { + // key带#代表设置了ttl,只保留#前的部分作为key + if (name.contains("#")) { + name = CharSequenceUtil.subBefore(name, "#", false); + } // 如果开启多组织,则 name 拼接组织后缀 if (!OrganContextHolder.isIgnore() - && OrganContextHolder.getOrganId() != null) { + && OrganContextHolder.getOrganId() != null + && !ignoreOrganIdKeyList.contains(name)) { name = name + ":" + OrganContextHolder.getOrganId(); } diff --git a/cf-framework/cf-spring-boot-starter-redis/src/main/java/com/cf/imes/framework/redis/core/TimeoutRedisCacheManager.java b/cf-framework/cf-spring-boot-starter-redis/src/main/java/com/cf/imes/framework/redis/core/TimeoutRedisCacheManager.java index d1cb6dcaf..01b1d07ed 100644 --- a/cf-framework/cf-spring-boot-starter-redis/src/main/java/com/cf/imes/framework/redis/core/TimeoutRedisCacheManager.java +++ b/cf-framework/cf-spring-boot-starter-redis/src/main/java/com/cf/imes/framework/redis/core/TimeoutRedisCacheManager.java @@ -41,12 +41,15 @@ public class TimeoutRedisCacheManager extends RedisCacheManager { // 核心:通过修改 cacheConfig 的过期时间,实现自定义过期时间 if (cacheConfig != null) { // 移除 # 后面的 : 以及后面的内容,避免影响解析 - names[1] = CharSequenceUtil.subBefore(names[1], StrPool.COLON, false); + String ttlStr = CharSequenceUtil.subBefore(names[1], StrPool.COLON, false); // 获得 ttlStr 时间部分 + names[1] = CharSequenceUtil.subAfter(names[1], ttlStr, false); // 移除掉 ttlStr 时间部分 // 解析时间 - Duration duration = parseDuration(names[1]); + Duration duration = parseDuration(ttlStr); cacheConfig = cacheConfig.entryTtl(duration); } - return super.createRedisCache(name, cacheConfig); + + // 创建 RedisCache 对象,需要忽略掉 ttlStr + return super.createRedisCache(names[0] + names[1], cacheConfig); } /** diff --git a/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java index 1657c81d9..a6d846630 100644 --- a/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java +++ b/cf-module-system/cf-module-system-api/src/main/java/com/cf/imes/module/system/enums/ErrorCodeConstants.java @@ -35,6 +35,8 @@ public class ErrorCodeConstants { public static final ErrorCode ROLE_ADMIN_CODE_ERROR = new ErrorCode(1_002_002_005, "编码【{}】不能使用"); public static final ErrorCode ROLE_ME_ERROR = new ErrorCode(1_002_002_006, "不可为自身分配角色"); public static final ErrorCode ROLE_NOT_SUPERADMIN_NO_ORGAN_ID_OPER_ERROR = new ErrorCode(1_002_002_007, "非超管分配权限"); + public static final ErrorCode BUILDIN_ROLE_MODIFY_PERMISSION_ERROR = new ErrorCode(1_002_002_008, "修改内置角色下菜单权限的权限不足"); + public static final ErrorCode SELF_ROLE_MODIFY_PERMISSION_ERROR = new ErrorCode(1_002_002_009, "无法修改自身的角色菜单权限"); // ========== 用户模块 1-002-003-000 ========== public static final ErrorCode USER_USERNAME_EXISTS = new ErrorCode(1_002_003_000, "手机号已经存在"); diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/auth/AuthController.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/auth/AuthController.java index 3555a54fd..cef864dc0 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/auth/AuthController.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/auth/AuthController.java @@ -1,12 +1,16 @@ package com.cf.imes.module.system.controller.admin.auth; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; import com.cf.imes.framework.common.enums.CommonStatusEnum; import com.cf.imes.framework.common.enums.UserTypeEnum; +import com.cf.imes.framework.common.exception.ServiceException; +import com.cf.imes.framework.common.exception.enums.GlobalErrorCodeConstants; import com.cf.imes.framework.common.pojo.CommonResult; import com.cf.imes.framework.common.validation.Mobile; import com.cf.imes.framework.operatelog.core.annotations.OperateLog; import com.cf.imes.framework.security.config.SecurityProperties; +import com.cf.imes.framework.security.core.LoginUser; import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils; import com.cf.imes.module.system.api.sms.dto.code.SmsCodeSendReqDTO; import com.cf.imes.module.system.controller.admin.auth.vo.AuthLoginReqVO; @@ -129,14 +133,19 @@ public class AuthController { @GetMapping("/get-permission-info") @Operation(summary = "获取登录用户的权限信息") public CommonResult getPermissionInfo() { + LoginUser loginUser = SecurityFrameworkUtils.getLoginUser(); + if (ObjectUtil.isNull(loginUser)) { + throw new ServiceException(GlobalErrorCodeConstants.UNAUTHORIZED); + } + Long userId = loginUser.getId(); // 1.1 获得用户信息 - AdminUserDO user = userService.getUser(getLoginUserId()); + AdminUserDO user = userService.getUser(userId); if (user == null) { return null; } // 1.2 获得角色列表 - Set roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId()); + Set roleIds = permissionService.getUserRoleIdListByUserId(userId); if (CollUtil.isEmpty(roleIds)) { return success(AuthConvert.INSTANCE.convert(user, Collections.emptyList(), Collections.emptyList())); } @@ -144,7 +153,7 @@ public class AuthController { roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色 // 1.3 获得菜单列表 - Set menuIds = permissionService.getRoleMenuListByRoleId2(convertSet(roles, RoleDO::getId)); + Set menuIds = permissionService.getRoleMenuListByRoleId2(convertSet(roles, RoleDO::getId), loginUser.getOrganId()); List menuList = menuService.getMenuList1(menuIds); menuList.removeIf(menu -> !CommonStatusEnum.ENABLE.getStatus().equals(menu.getStatus())); // 移除禁用的菜单 diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/permission/MenuController.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/permission/MenuController.java index a3d1a6264..7790cb5e3 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/permission/MenuController.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/permission/MenuController.java @@ -1,7 +1,10 @@ package com.cf.imes.module.system.controller.admin.permission; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; import com.cf.imes.framework.common.enums.CommonStatusEnum; +import com.cf.imes.framework.common.exception.ServiceException; +import com.cf.imes.framework.common.exception.enums.GlobalErrorCodeConstants; import com.cf.imes.framework.common.pojo.CommonResult; import com.cf.imes.framework.common.util.object.BeanUtils; import com.cf.imes.framework.security.core.LoginUser; @@ -30,7 +33,6 @@ import java.util.*; import static com.cf.imes.framework.common.pojo.CommonResult.success; import static com.cf.imes.framework.common.util.collection.CollectionUtils.convertSet; import static com.cf.imes.framework.security.core.util.SecurityFrameworkUtils.getLoginUser; -import static com.cf.imes.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; @Tag(name = "管理后台 - 菜单") @RestController @@ -79,24 +81,29 @@ public class MenuController { @Operation(summary = "获取菜单列表", description = "用于【菜单管理】界面") //@PreAuthorize("@ss.hasPermission('system:menu:query')") public CommonResult> getMenuList(MenuListReqVO reqVO) { - List list = null; + List list; LoginUser loginUser = getLoginUser(); + if (ObjectUtil.isNull(loginUser)) { + throw new ServiceException(GlobalErrorCodeConstants.UNAUTHORIZED); + } + if(loginUser.getIsSupAdmin()) { list = menuService.getMenuList(reqVO); }else { - AdminUserDO user = userService.getUser(getLoginUserId()); + AdminUserDO user = userService.getUser(loginUser.getId()); if (user == null) { return success(new ArrayList<>()); } - Set roleIds = permissionService.getUserRoleIdListByUserId(getLoginUserId()); + // 获取登录用户所属角色 + Set roleIds = permissionService.getUserRoleIdListByUserId(loginUser.getId()); if (CollUtil.isEmpty(roleIds)) { return success(new ArrayList<>()); } - //List roles = roleService.getRoleList(roleIds); + // 查询角色并过滤无效的 List roles = roleService.getRoleList1(roleIds); roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色 - Set menuIds = permissionService.getRoleMenuListByRoleId2(convertSet(roles, RoleDO::getId)); - //List menuList = menuService.getMenuList(menuIds); + // 查询角色拥有权限的菜单id + Set menuIds = permissionService.getRoleMenuListByRoleId2(convertSet(roles, RoleDO::getId), loginUser.getOrganId()); list = menuService.getMenuList1(menuIds); list.removeIf(menu -> !CommonStatusEnum.ENABLE.getStatus().equals(menu.getStatus())); // 移除禁用的菜单 } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/permission/PermissionController.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/permission/PermissionController.java index 1e4597809..af0f45e63 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/permission/PermissionController.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/controller/admin/permission/PermissionController.java @@ -11,6 +11,7 @@ import com.cf.imes.module.system.controller.admin.permission.vo.permission.Permi import com.cf.imes.module.system.controller.admin.permission.vo.permission.PermissionAssignRoleMenuReqVO; import com.cf.imes.module.system.controller.admin.permission.vo.permission.PermissionAssignRoleUserReqVO; import com.cf.imes.module.system.controller.admin.permission.vo.permission.PermissionAssignUserRoleReqVO; +import com.cf.imes.module.system.enums.ErrorCodeConstants; import com.cf.imes.module.system.service.permission.PermissionService; import com.cf.imes.module.system.service.organ.OrganService; import io.swagger.v3.oas.annotations.Operation; @@ -59,14 +60,14 @@ public class PermissionController { LoginUser loginUser = SecurityFrameworkUtils.getLoginUser(); boolean isOrganRole = Objects.equals(reqVO.getRoleId(), InternalRoleConstants.ORGAN_ADMIN_ROLE_ID) || Objects.equals(reqVO.getRoleId(), InternalRoleConstants.ORGAN_STAFF_ROLE_ID); if(!loginUser.getIsSupAdmin() && (isOrganRole)) { - throw new ServiceException(11541, "内置角色无权修改菜单权限"); + throw new ServiceException(ErrorCodeConstants.BUILDIN_ROLE_MODIFY_PERMISSION_ERROR); } if(Objects.equals(reqVO.getRoleId(), 1L)) { - throw new ServiceException(11541, "内置角色无权修改菜单权限"); + throw new ServiceException(ErrorCodeConstants.BUILDIN_ROLE_MODIFY_PERMISSION_ERROR); } Set roleIds = permissionService.getUserRoleIdListByUserId(loginUser.getId()); if (roleIds.contains(reqVO.getRoleId())) { - throw new ServiceException(11541, "无法修改自身的角色菜单权限"); + throw new ServiceException(ErrorCodeConstants.SELF_ROLE_MODIFY_PERMISSION_ERROR); } if (!isOrganRole) { diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/redis/RedisKeyConstants.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/redis/RedisKeyConstants.java index 10a401062..4cc10f3eb 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/redis/RedisKeyConstants.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/redis/RedisKeyConstants.java @@ -108,4 +108,10 @@ public class RedisKeyConstants { * 短信验证码次数上限的缓存 */ public static final String SMS_CAPTCHA_VERIFICATION_LIMIT = "sms_captcha_verification_limit:%s"; -} + + /** + * 套餐下的权限菜单id:12h代表key的ttl为12小时 + * !!!!注意同步修改OrganRedisCacheManager中的key字符串 + */ + public static final String TENANT_PACKAGE_MENU_IDS = "tenant_package_menu_ids#12h"; +} \ No newline at end of file diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/redis/listener/SystemPermissionRefreshRedisListener.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/redis/listener/SystemPermissionRefreshRedisListener.java index a9fdfb661..695f2a5de 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/redis/listener/SystemPermissionRefreshRedisListener.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/dal/redis/listener/SystemPermissionRefreshRedisListener.java @@ -3,6 +3,7 @@ package com.cf.imes.module.system.dal.redis.listener; import com.cf.imes.framework.mq.redis.core.pubsub.AbstractRedisSimpleMessageListener; import com.cf.imes.framework.security.core.service.SecurityFrameworkService; import com.cf.imes.module.system.dal.redis.RedisRefreshChannelTopicConstants; +import lombok.extern.slf4j.Slf4j; import org.springframework.data.redis.connection.Message; import org.springframework.data.redis.listener.ChannelTopic; import org.springframework.stereotype.Component; @@ -14,6 +15,7 @@ import org.springframework.stereotype.Component; * @since 2024/6/13 10:32 */ @Component +@Slf4j public class SystemPermissionRefreshRedisListener extends AbstractRedisSimpleMessageListener { private final SecurityFrameworkService securityFrameworkService; @@ -25,6 +27,7 @@ public class SystemPermissionRefreshRedisListener extends AbstractRedisSimpleMes @Override public void onMessage(Message message, byte[] bytes) { + log.info("[SystemPermissionRefreshRedisListener][onMessage][{}收到刷新本地权限缓存]", message); securityFrameworkService.invalidateAllPermissionsCache(); } } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/organ/OrganService.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/organ/OrganService.java index c0d23c792..946597dd3 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/organ/OrganService.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/organ/OrganService.java @@ -131,7 +131,7 @@ public interface OrganService { * * @param id 组织编号 */ - void validOrgan(Long id); + OrganizationDO validOrgan(Long id); List getSimpleOrganList(String name); diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/organ/OrganServiceImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/organ/OrganServiceImpl.java index 7b687fd8a..ce62f758b 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/organ/OrganServiceImpl.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/organ/OrganServiceImpl.java @@ -101,7 +101,7 @@ public class OrganServiceImpl implements OrganService { } @Override - public void validOrgan(Long id) { + public OrganizationDO validOrgan(Long id) { OrganizationDO organizationDO = getOrgan(id); if (organizationDO == null) { throw exception(ORGAN_NOT_EXISTS); @@ -112,6 +112,10 @@ public class OrganServiceImpl implements OrganService { if (DateUtils.isExpired(organizationDO.getExpireTime())) { throw exception(ORGAN_EXPIRE, organizationDO.getName()); } + if (ObjectUtil.isNull(organizationDO.getPackageId())) { + throw exception(TENANT_PACKAGE_NOT_EXISTS); + } + return organizationDO; } @Override @@ -216,7 +220,7 @@ public class OrganServiceImpl implements OrganService { organMapper.updateById(updateObj); // 如果套餐发生变化,则修改其角色的权限 if (ObjectUtil.notEqual(tenant.getPackageId(), updateReqVO.getPackageId())) { - updateOrganRoleMenu(tenant.getId(), tenantPackage.getMenuIds()); + permissionService.flushCacheWhenTenantPackageChange(List.of(tenant.getId())); } } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/organ/TenantPackageService.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/organ/TenantPackageService.java index 0bf009cdf..f97f500bc 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/organ/TenantPackageService.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/organ/TenantPackageService.java @@ -7,6 +7,7 @@ import com.cf.imes.module.system.dal.dataobject.organ.TenantPackageDO; import javax.validation.Valid; import java.util.List; +import java.util.Set; /** * 组织套餐 Service 接口 @@ -72,4 +73,11 @@ public interface TenantPackageService { */ List getTenantPackageListByStatus(Integer status); + /** + * 获取组织套餐下的权限菜单id + * + * @param id 组织套餐id + * @return + */ + Set getTenantPackageMenuIds(Long id); } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/organ/TenantPackageServiceImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/organ/TenantPackageServiceImpl.java index ab2c6f778..5a0a835c1 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/organ/TenantPackageServiceImpl.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/organ/TenantPackageServiceImpl.java @@ -5,6 +5,7 @@ import cn.hutool.core.util.ObjectUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.cf.imes.framework.common.enums.CommonStatusEnum; import com.cf.imes.framework.common.pojo.PageResult; +import com.cf.imes.framework.common.util.collection.CollectionUtils; import com.cf.imes.framework.common.util.object.BeanUtils; import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX; import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils; @@ -14,6 +15,10 @@ import com.cf.imes.module.system.dal.dataobject.organ.OrganizationDO; import com.cf.imes.module.system.dal.dataobject.organ.TenantPackageDO; import com.cf.imes.module.system.dal.mysql.organ.TenantPackageMapper; import com.baomidou.dynamic.datasource.annotation.DSTransactional; +import com.cf.imes.module.system.dal.redis.RedisKeyConstants; +import com.cf.imes.module.system.service.permission.PermissionService; +import org.springframework.cache.annotation.CacheEvict; +import org.springframework.cache.annotation.Cacheable; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Service; import org.springframework.validation.annotation.Validated; @@ -21,6 +26,7 @@ import org.springframework.validation.annotation.Validated; import javax.annotation.Resource; import java.util.List; import java.util.Objects; +import java.util.Set; import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception; import static com.cf.imes.module.system.enums.ErrorCodeConstants.*; @@ -41,7 +47,11 @@ public class TenantPackageServiceImpl implements TenantPackageService { @Lazy // 避免循环依赖的报错 private OrganService organService; + @Resource + private PermissionService permissionService; + @Override + @CacheEvict(value = RedisKeyConstants.TENANT_PACKAGE_MENU_IDS, key = "#createReqVO.id") public Long createTenantPackage(TenantPackageSaveReqVO createReqVO) { // 唯一性校验 validateTenantPackageUnique(createReqVO); @@ -54,6 +64,7 @@ public class TenantPackageServiceImpl implements TenantPackageService { @Override @DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换 + @CacheEvict(value = RedisKeyConstants.TENANT_PACKAGE_MENU_IDS, key = "#updateReqVO.id") public void updateTenantPackage(TenantPackageSaveReqVO updateReqVO) { // 唯一性校验 validateTenantPackageUnique(updateReqVO); @@ -70,11 +81,12 @@ public class TenantPackageServiceImpl implements TenantPackageService { // 如果菜单发生变化,则修改每个组织的菜单 if (!CollUtil.isEqualList(tenantPackage.getMenuIds(), updateReqVO.getMenuIds())) { List tenants = organService.getOrganListByPackageId(tenantPackage.getId()); - tenants.forEach(tenant -> organService.updateOrganRoleMenu(tenant.getId(), updateReqVO.getMenuIds())); + permissionService.flushCacheWhenTenantPackageChange(CollectionUtils.convertList(tenants, OrganizationDO::getId)); } } @Override + @CacheEvict(value = RedisKeyConstants.TENANT_PACKAGE_MENU_IDS, key = "#id") public void deleteTenantPackage(Long id) { // 校验存在 validateTenantPackageExists(id); @@ -144,4 +156,15 @@ public class TenantPackageServiceImpl implements TenantPackageService { return tenantPackageMapper.selectListByStatus(status); } + @Override + @Cacheable(value = RedisKeyConstants.TENANT_PACKAGE_MENU_IDS, key = "#id", unless = "#result == null", cacheManager = "redisCacheManager") + public Set getTenantPackageMenuIds(Long id) { + validateTenantPackageExists(id); + TenantPackageDO tenantPackageDO = tenantPackageMapper.selectOne(new LambdaQueryWrapper().eq(TenantPackageDO::getId, id).select(TenantPackageDO::getMenuIds)); + if (ObjectUtil.isNotNull(tenantPackageDO)) { + return tenantPackageDO.getMenuIds(); + } else { + return null; + } + } } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/permission/PermissionService.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/permission/PermissionService.java index 324021b33..dd096d564 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/permission/PermissionService.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/permission/PermissionService.java @@ -154,7 +154,14 @@ public interface PermissionService { */ DeptDataPermissionRespDTO getDeptDataPermission(Long userId); - Set getRoleMenuListByRoleId2(Set roleIds); + /** + * 查询角色id列表下所拥有的权限菜单,通过组织所配的菜单做过滤 + * + * @param roleIds 角色id列表 + * @param organId 组织id + * @return + */ + Set getRoleMenuListByRoleId2(Set roleIds,Long organId); void bathAssignUserRole(List listReqVO); @@ -181,4 +188,11 @@ public interface PermissionService { * 判断用户是否拥有相对应的权限 */ Boolean hasPermission(Long userId, String permission); + + /** + * 组织套餐发生改变刷新缓存 + * + * @param organIds 组织id列表 + */ + void flushCacheWhenTenantPackageChange(List organIds); } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/permission/PermissionServiceImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/permission/PermissionServiceImpl.java index 33f42a024..574c56da9 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/permission/PermissionServiceImpl.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/permission/PermissionServiceImpl.java @@ -6,6 +6,7 @@ import cn.hutool.core.util.ObjectUtil; import cn.hutool.extra.spring.SpringUtil; import com.cf.imes.framework.common.enums.CommonStatusEnum; import com.cf.imes.framework.common.exception.ServiceException; +import com.cf.imes.framework.common.exception.enums.GlobalErrorCodeConstants; import com.cf.imes.framework.common.util.collection.CollectionUtils; import com.cf.imes.framework.common.util.json.JsonUtils; import com.cf.imes.framework.datapermission.core.annotation.DataPermission; @@ -19,10 +20,12 @@ import com.cf.imes.module.system.constants.permission.InternalRoleConstants; import com.cf.imes.module.system.controller.admin.permission.vo.permission.PermissionAssignRoleUserReqVO; import com.cf.imes.module.system.controller.admin.permission.vo.permission.PermissionAssignUserRoleReqVO; import com.cf.imes.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO; +import com.cf.imes.module.system.dal.dataobject.organ.OrganizationDO; import com.cf.imes.module.system.dal.dataobject.permission.MenuDO; import com.cf.imes.module.system.dal.dataobject.permission.RoleDO; import com.cf.imes.module.system.dal.dataobject.permission.RoleMenuDO; import com.cf.imes.module.system.dal.dataobject.permission.UserRoleDO; +import com.cf.imes.module.system.dal.dataobject.user.AdminUserDO; import com.cf.imes.module.system.dal.mysql.permission.RoleMenuMapper; import com.cf.imes.module.system.dal.mysql.permission.UserRoleMapper; import com.cf.imes.module.system.dal.redis.RedisKeyConstants; @@ -30,6 +33,8 @@ import com.cf.imes.module.system.dal.redis.RedisRefreshChannelTopicConstants; import com.cf.imes.module.system.enums.ErrorCodeConstants; import com.cf.imes.module.system.enums.permission.DataScopeEnum; import com.cf.imes.module.system.service.dept.DeptService; +import com.cf.imes.module.system.service.organ.OrganService; +import com.cf.imes.module.system.service.organ.TenantPackageService; import com.cf.imes.module.system.service.user.AdminUserService; import com.baomidou.dynamic.datasource.annotation.DSTransactional; import com.cf.imes.module.system.util.organ.OrganUtils; @@ -40,6 +45,7 @@ import lombok.extern.slf4j.Slf4j; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.cache.annotation.Caching; +import org.springframework.context.annotation.Lazy; import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.ScanOptions; import org.springframework.data.redis.core.StringRedisTemplate; @@ -56,7 +62,7 @@ import java.util.stream.Collectors; import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception; import static com.cf.imes.framework.common.util.collection.CollectionUtils.convertSet; import static com.cf.imes.framework.common.util.json.JsonUtils.toJsonString; -import static com.cf.imes.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; +import static com.cf.imes.framework.security.core.util.SecurityFrameworkUtils.getLoginUser; import static com.cf.imes.module.system.dal.redis.RedisKeyConstants.OAUTH2_ACCESS_TOKEN; import static com.cf.imes.module.system.enums.ErrorCodeConstants.ROLE_ME_ERROR; @@ -86,6 +92,14 @@ public class PermissionServiceImpl implements PermissionService { @Resource private StringRedisTemplate stringRedisTemplate; + @Resource + @Lazy // 延迟,避免循环依赖报错 + private TenantPackageService tenantPackageService; + + @Resource + @Lazy // 延迟,避免循环依赖报错 + private OrganService organService; + @Override public boolean hasAnyPermissions(Long userId, String... permissions) { // 如果为空,说明已经有权限 @@ -99,9 +113,15 @@ public class PermissionServiceImpl implements PermissionService { return false; } + AdminUserDO user = userService.getUser(userId); + if (ObjectUtil.isNull(user)) { + throw new ServiceException(ErrorCodeConstants.USER_NOT_EXISTS); + } + OrganizationDO organizationDO = organService.validOrgan(user.getOrganId()); + // 情况一:遍历判断每个权限,如果有一满足,说明有权限 for (String permission : permissions) { - if (hasAnyPermission(roles, permission)) { + if (hasAnyPermission(roles, permission, organizationDO.getPackageId())) { return true; } } @@ -117,13 +137,16 @@ public class PermissionServiceImpl implements PermissionService { * @param permission 权限标识 * @return 是否拥有 */ - private boolean hasAnyPermission(List roles, String permission) { + private boolean hasAnyPermission(List roles, String permission, Long packageId) { List menuIds = menuService.getMenuIdListByPermissionFromCache(permission); // 采用严格模式,如果权限找不到对应的 Menu 的话,也认为没有权限 if (CollUtil.isEmpty(menuIds)) { return false; } + // 组织套餐下的菜单 + Set tenantPackageMenuIds = tenantPackageService.getTenantPackageMenuIds(packageId); + // 判断是否有权限 Set roleIds = convertSet(roles, RoleDO::getId); for (Long menuId : menuIds) { @@ -131,7 +154,8 @@ public class PermissionServiceImpl implements PermissionService { //Set menuRoleIds = getSelf().getMenuRoleIdListByMenuIdFromCache(menuId); Set menuRoleIds = getSelf().getMenuRoleIdListByMenuIdFromCache1(menuId); // 如果有交集,说明有权限 - if (CollUtil.containsAny(menuRoleIds, roleIds)) { + // 角色下菜单id和组织套餐内菜单id必须同时满足 + if (CollUtil.containsAny(menuRoleIds, roleIds) && tenantPackageMenuIds.contains(menuId)) { return true; } } @@ -241,7 +265,9 @@ public class PermissionServiceImpl implements PermissionService { } else { userIds = userRoleMapper.selectOrgRoleUserIds(roleId).stream().map(UserRoleDO::getUserId).toList(); } - scanAndCompareUserAndDelKeys(String.format(OAUTH2_ACCESS_TOKEN, "*"), userIds); + if (CollUtil.isNotEmpty(userIds)) { + scanAndCompareUserAndDelKeys(String.format(OAUTH2_ACCESS_TOKEN, "*"), userIds); + } }) .exceptionally(e -> { log.error("[assignRoleMenu][flushRoleMenuCache]失败, 异常:{}", e); @@ -353,7 +379,7 @@ public class PermissionServiceImpl implements PermissionService { @Override @OrganIgnore - public Set getRoleMenuListByRoleId2(Set roleIds) { + public Set getRoleMenuListByRoleId2(Set roleIds, Long organId) { if (CollUtil.isEmpty(roleIds)) { return Collections.emptySet(); } @@ -361,17 +387,27 @@ public class PermissionServiceImpl implements PermissionService { // 如果是管理员的情况下,获取全部菜单编号 if (roleService.hasAnySuperAdmin(roleIds)) { return convertSet(menuService.getMenuList(), MenuDO::getId); - } - List buildinRoleIdList = new ArrayList<>(){{ - add(InternalRoleConstants.ORGAN_ADMIN_ROLE_ID); - add(InternalRoleConstants.ORGAN_STAFF_ROLE_ID); - }}; - if (CollUtil.containsAny(roleIds, buildinRoleIdList)) { - // 内置角色不限制组织id - return convertSet(roleMenuMapper.selectListByRoleId(roleIds), RoleMenuDO::getMenuId); } else { - // 普通成员只能看组织id下的菜单 - return convertSet(roleMenuMapper.selectListByRoleIdsAndOrganId(roleIds, OrganContextHolder.getOrganId()), RoleMenuDO::getMenuId); + List buildinRoleIdList = new ArrayList<>(){{ + add(InternalRoleConstants.ORGAN_ADMIN_ROLE_ID); + add(InternalRoleConstants.ORGAN_STAFF_ROLE_ID); + }}; + + Set roleMenuIds; + if (CollUtil.containsAny(roleIds, buildinRoleIdList)) { + // 内置角色不限制组织id + roleMenuIds = convertSet(roleMenuMapper.selectListByRoleId(roleIds), RoleMenuDO::getMenuId); + } else { + // 普通成员只能看组织id下的菜单 + roleMenuIds = convertSet(roleMenuMapper.selectListByRoleIdsAndOrganId(roleIds, OrganContextHolder.getOrganId()), RoleMenuDO::getMenuId); + } + + // 校验、获取可用的组织 + OrganizationDO organ = organService.validOrgan(organId); + + Set tenantPackageMenuIds = tenantPackageService.getTenantPackageMenuIds(organ.getPackageId()); + + return Sets.intersection(roleMenuIds, tenantPackageMenuIds); } } @@ -677,8 +713,12 @@ public class PermissionServiceImpl implements PermissionService { */ @Override public Set getUserPermissions(Long userId) { + LoginUser loginUser = getLoginUser(); + if (ObjectUtil.isNull(loginUser)) { + throw new ServiceException(GlobalErrorCodeConstants.UNAUTHORIZED); + } // 1.2 获得角色列表 - Set roleIds = getUserRoleIdListByUserId(getLoginUserId()); + Set roleIds = getUserRoleIdListByUserId(loginUser.getId()); if (CollUtil.isEmpty(roleIds)) { return Collections.emptySet(); } @@ -686,7 +726,7 @@ public class PermissionServiceImpl implements PermissionService { roles.removeIf(role -> !CommonStatusEnum.ENABLE.getStatus().equals(role.getStatus())); // 移除禁用的角色 // 1.3 获得菜单列表 - Set menuIds = getRoleMenuListByRoleId2(convertSet(roles, RoleDO::getId)); + Set menuIds = getRoleMenuListByRoleId2(convertSet(roles, RoleDO::getId), loginUser.getOrganId()); List menuList = menuService.getMenuList1(menuIds); menuList.removeIf(menu -> !CommonStatusEnum.ENABLE.getStatus().equals(menu.getStatus())); // 移除禁用的菜单 @@ -699,4 +739,28 @@ public class PermissionServiceImpl implements PermissionService { return permissions.contains(permission); } + @Override + public void flushCacheWhenTenantPackageChange(List organIds) { + if (CollUtil.isEmpty(organIds)) { + return; + } + CompletableFuture.runAsync(() -> { + for (Long organId : organIds) { + // 清空机构下的用户的token缓存 + List organUsers = userService.getOrganUsers(organId); + if (CollUtil.isNotEmpty(organUsers)) { + List userIds = CollectionUtils.convertList(organUsers, AdminUserDO::getId); + scanAndCompareUserAndDelKeys(String.format(OAUTH2_ACCESS_TOKEN, "*"), userIds); + } + } + }) + .thenRunAsync(() -> { + //通知刷新本地权限缓存 + stringRedisTemplate.convertAndSend(RedisRefreshChannelTopicConstants.PERMISSION_REFRESH, ""); + }) + .exceptionally(e -> { + log.error("[PermissionService][flushCacheWhenTenantPackageChange]失败, 异常:{}", e); + return null; + }); + } } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/user/AdminUserService.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/user/AdminUserService.java index 74f157724..4cac2da08 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/user/AdminUserService.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/user/AdminUserService.java @@ -281,4 +281,12 @@ public interface AdminUserService { * @param reqVO 用户个人信息 */ void updateUserSecurityPhone(Long id, @Valid UserMobileUpdateReqVO reqVO); + + /** + * 获取机构下的用户 + * + * @param organId + * @return + */ + List getOrganUsers(Long organId); } diff --git a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/user/AdminUserServiceImpl.java b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/user/AdminUserServiceImpl.java index 9eb38dd04..444e4cd0d 100644 --- a/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/user/AdminUserServiceImpl.java +++ b/cf-module-system/cf-module-system-biz/src/main/java/com/cf/imes/module/system/service/user/AdminUserServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.io.IoUtil; import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import com.cf.imes.framework.common.enums.CommonStatusEnum; import com.cf.imes.framework.common.enums.UserTypeEnum; @@ -784,4 +785,10 @@ public class AdminUserServiceImpl implements AdminUserService { // 将时间设置为 0 点 return LocalDateTime.of(firstDayOfMonth, LocalTime.MIDNIGHT); } + + @Override + @OrganIgnore + public List getOrganUsers(Long organId) { + return userMapper.selectList(new LambdaQueryWrapper().eq(AdminUserDO::getOrganId, organId)); + } }