From 8737674d743ea2bcfdb0a50a0d7f007c58753884 Mon Sep 17 00:00:00 2001 From: YunaiV Date: Sat, 7 May 2022 00:39:39 +0800 Subject: [PATCH] =?UTF-8?q?=E5=8E=BB=E9=99=A4=20LoginUser=20=E7=9A=84=20ro?= =?UTF-8?q?leIds=E3=80=81deptId=20=E5=AD=97=E6=AE=B5=EF=BC=8C=E7=AE=80?= =?UTF-8?q?=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- yudao-dependencies/pom.xml | 7 -- .../util/collection/CollectionUtils.java | 7 ++ .../dept/rule/DeptDataPermissionRule.java | 39 ++++-- .../DeptDataPermissionFrameworkService.java | 5 +- .../dept/rule/DeptDataPermissionRuleTest.java | 40 ++++-- .../framework/security/core/LoginUser.java | 11 -- .../core/util/SecurityFrameworkUtils.java | 12 -- .../service/auth/MemberAuthServiceImpl.java | 2 +- .../controller/admin/auth/AuthController.java | 18 +-- .../admin/auth/UserSessionController.java | 12 +- .../service/auth/AdminAuthServiceImpl.java | 23 +--- .../permission/PermissionServiceImpl.java | 54 ++++---- .../service/tenant/TenantServiceImpl.java | 1 + .../service/user/AdminUserServiceImpl.java | 2 + .../service/auth/AuthServiceImplTest.java | 17 +-- .../permission/PermissionServiceTest.java | 118 ++++++++++-------- 16 files changed, 179 insertions(+), 189 deletions(-) diff --git a/yudao-dependencies/pom.xml b/yudao-dependencies/pom.xml index 5a7e152ae..63913572a 100644 --- a/yudao-dependencies/pom.xml +++ b/yudao-dependencies/pom.xml @@ -22,7 +22,6 @@ 1.5.22 2.5 - 5.1.46 1.2.8 3.4.3.4 3.5.2 @@ -76,12 +75,6 @@ ${spring.boot.version} pom import - - - mysql - mysql-connector-java - - diff --git a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java index 1ea74ee29..a6466ab44 100644 --- a/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java +++ b/yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java @@ -54,6 +54,13 @@ public class CollectionUtils { return from.stream().map(func).filter(Objects::nonNull).collect(Collectors.toList()); } + public static List convertList(Collection from, Function func, Predicate filter) { + if (CollUtil.isEmpty(from)) { + return new ArrayList<>(); + } + return from.stream().filter(filter).map(func).filter(Objects::nonNull).collect(Collectors.toList()); + } + public static Set convertSet(Collection from, Function func) { if (CollUtil.isEmpty(from)) { return new HashSet<>(); diff --git a/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/rule/DeptDataPermissionRule.java b/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/rule/DeptDataPermissionRule.java index ed9168ba0..2a0c9aefa 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/rule/DeptDataPermissionRule.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/rule/DeptDataPermissionRule.java @@ -1,11 +1,13 @@ package cn.iocoder.yudao.framework.datapermission.core.dept.rule; import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; -import cn.iocoder.yudao.framework.datapermission.core.dept.service.DeptDataPermissionFrameworkService; -import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.datapermission.core.dept.service.DeptDataPermissionFrameworkService; +import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO; import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule; import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; @@ -13,7 +15,6 @@ import cn.iocoder.yudao.framework.security.core.LoginUser; import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; import lombok.AllArgsConstructor; -import lombok.Getter; import lombok.extern.slf4j.Slf4j; import net.sf.jsqlparser.expression.Alias; import net.sf.jsqlparser.expression.Expression; @@ -24,10 +25,7 @@ import net.sf.jsqlparser.expression.operators.relational.EqualsTo; import net.sf.jsqlparser.expression.operators.relational.ExpressionList; import net.sf.jsqlparser.expression.operators.relational.InExpression; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; +import java.util.*; /** * 基于部门的 {@link DataPermissionRule} 数据权限规则实现 @@ -50,6 +48,11 @@ import java.util.Set; @Slf4j public class DeptDataPermissionRule implements DataPermissionRule { + /** + * LoginUser 的 Context 缓存 Key + */ + protected static final String CONTEXT_KEY = DeptDataPermissionRule.class.getSimpleName(); + private static final String DEPT_COLUMN_NAME = "dept_id"; private static final String USER_COLUMN_NAME = "user_id"; @@ -90,13 +93,23 @@ public class DeptDataPermissionRule implements DataPermissionRule { if (loginUser == null) { return null; } + // 只有管理员类型的用户,才进行数据权限的处理 + if (ObjectUtil.notEqual(loginUser.getUserType(), UserTypeEnum.ADMIN.getValue())) { + return null; + } // 获得数据权限 - DeptDataPermissionRespDTO deptDataPermission = deptDataPermissionService.getDeptDataPermission(loginUser); + DeptDataPermissionRespDTO deptDataPermission = loginUser.getContext(CONTEXT_KEY, DeptDataPermissionRespDTO.class); + // 从上下文中拿不到,则调用逻辑进行获取 if (deptDataPermission == null) { - log.error("[getExpression][LoginUser({}) 获取数据权限为 null]", JsonUtils.toJsonString(loginUser)); - throw new NullPointerException(String.format("LoginUser(%d) Table(%s/%s) 未返回数据权限", - loginUser.getId(), tableName, tableAlias.getName())); + deptDataPermission = deptDataPermissionService.getDeptDataPermission(loginUser.getId()); + if (deptDataPermission == null) { + log.error("[getExpression][LoginUser({}) 获取数据权限为 null]", JsonUtils.toJsonString(loginUser)); + throw new NullPointerException(String.format("LoginUser(%d) Table(%s/%s) 未返回数据权限", + loginUser.getId(), tableName, tableAlias.getName())); + } + // 添加到上下文中,避免重复计算 + loginUser.setContext(CONTEXT_KEY, deptDataPermission); } // 情况一,如果是 ALL 可查看全部,则无需拼接条件 @@ -111,8 +124,8 @@ public class DeptDataPermissionRule implements DataPermissionRule { } // 情况三,拼接 Dept 和 User 的条件,最后组合 - Expression deptExpression = this.buildDeptExpression(tableName,tableAlias, deptDataPermission.getDeptIds()); - Expression userExpression = this.buildUserExpression(tableName, tableAlias, deptDataPermission.getSelf(), loginUser.getId()); + Expression deptExpression = buildDeptExpression(tableName,tableAlias, deptDataPermission.getDeptIds()); + Expression userExpression = buildUserExpression(tableName, tableAlias, deptDataPermission.getSelf(), loginUser.getId()); if (deptExpression == null && userExpression == null) { // TODO 芋艿:获得不到条件的时候,暂时不抛出异常,而是不返回数据 log.warn("[getExpression][LoginUser({}) Table({}/{}) DeptDataPermission({}) 构建的条件为空]", diff --git a/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/service/DeptDataPermissionFrameworkService.java b/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/service/DeptDataPermissionFrameworkService.java index 3ee616755..e491aa036 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/service/DeptDataPermissionFrameworkService.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/service/DeptDataPermissionFrameworkService.java @@ -1,7 +1,6 @@ package cn.iocoder.yudao.framework.datapermission.core.dept.service; import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO; -import cn.iocoder.yudao.framework.security.core.LoginUser; /** * 基于部门的数据权限 Framework Service 接口 @@ -14,9 +13,9 @@ public interface DeptDataPermissionFrameworkService { /** * 获得登陆用户的部门数据权限 * - * @param loginUser 登陆用户 + * @param userId 用户编号 * @return 部门数据权限 */ - DeptDataPermissionRespDTO getDeptDataPermission(LoginUser loginUser); + DeptDataPermissionRespDTO getDeptDataPermission(Long userId); } diff --git a/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/dept/rule/DeptDataPermissionRuleTest.java b/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/dept/rule/DeptDataPermissionRuleTest.java index 7282c1816..ef5ff16ac 100644 --- a/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/dept/rule/DeptDataPermissionRuleTest.java +++ b/yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/dept/rule/DeptDataPermissionRuleTest.java @@ -2,6 +2,7 @@ package cn.iocoder.yudao.framework.datapermission.core.dept.rule; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.ReflectUtil; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; import cn.iocoder.yudao.framework.common.util.collection.SetUtils; import cn.iocoder.yudao.framework.datapermission.core.dept.service.DeptDataPermissionFrameworkService; import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO; @@ -69,7 +70,8 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest { String tableName = "t_user"; Alias tableAlias = new Alias("u"); // mock 方法 - LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)); + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L) + .setUserType(UserTypeEnum.ADMIN.getValue())); securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser); // 调用 @@ -88,16 +90,18 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest { String tableName = "t_user"; Alias tableAlias = new Alias("u"); // mock 方法(LoginUser) - LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)); + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L) + .setUserType(UserTypeEnum.ADMIN.getValue())); securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser); // mock 方法(DeptDataPermissionRespDTO) DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO().setAll(true); - when(deptDataPermissionFrameworkService.getDeptDataPermission(same(loginUser))).thenReturn(deptDataPermission); + when(deptDataPermissionFrameworkService.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission); // 调用 Expression expression = rule.getExpression(tableName, tableAlias); // 断言 assertNull(expression); + assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class)); } } @@ -109,16 +113,18 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest { String tableName = "t_user"; Alias tableAlias = new Alias("u"); // mock 方法(LoginUser) - LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)); + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L) + .setUserType(UserTypeEnum.ADMIN.getValue())); securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser); // mock 方法(DeptDataPermissionRespDTO) DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO(); - when(deptDataPermissionFrameworkService.getDeptDataPermission(same(loginUser))).thenReturn(deptDataPermission); + when(deptDataPermissionFrameworkService.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission); // 调用 Expression expression = rule.getExpression(tableName, tableAlias); // 断言 assertEquals("null = null", expression.toString()); + assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class)); } } @@ -130,17 +136,19 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest { String tableName = "t_user"; Alias tableAlias = new Alias("u"); // mock 方法(LoginUser) - LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)); + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L) + .setUserType(UserTypeEnum.ADMIN.getValue())); securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser); // mock 方法(DeptDataPermissionRespDTO) DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO() .setDeptIds(SetUtils.asSet(10L, 20L)).setSelf(true); - when(deptDataPermissionFrameworkService.getDeptDataPermission(same(loginUser))).thenReturn(deptDataPermission); + when(deptDataPermissionFrameworkService.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission); // 调用 Expression expression = rule.getExpression(tableName, tableAlias); // 断言 assertSame(EXPRESSION_NULL, expression); + assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class)); } } @@ -152,12 +160,13 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest { String tableName = "t_user"; Alias tableAlias = new Alias("u"); // mock 方法(LoginUser) - LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)); + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L) + .setUserType(UserTypeEnum.ADMIN.getValue())); securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser); // mock 方法(DeptDataPermissionRespDTO) DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO() .setSelf(true); - when(deptDataPermissionFrameworkService.getDeptDataPermission(same(loginUser))).thenReturn(deptDataPermission); + when(deptDataPermissionFrameworkService.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission); // 添加 user 字段配置 rule.addUserColumn("t_user", "id"); @@ -165,6 +174,7 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest { Expression expression = rule.getExpression(tableName, tableAlias); // 断言 assertEquals("u.id = 1", expression.toString()); + assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class)); } } @@ -176,12 +186,13 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest { String tableName = "t_user"; Alias tableAlias = new Alias("u"); // mock 方法(LoginUser) - LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)); + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L) + .setUserType(UserTypeEnum.ADMIN.getValue())); securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser); // mock 方法(DeptDataPermissionRespDTO) DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO() .setDeptIds(CollUtil.newLinkedHashSet(10L, 20L)); - when(deptDataPermissionFrameworkService.getDeptDataPermission(same(loginUser))).thenReturn(deptDataPermission); + when(deptDataPermissionFrameworkService.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission); // 添加 dept 字段配置 rule.addDeptColumn("t_user", "dept_id"); @@ -189,6 +200,7 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest { Expression expression = rule.getExpression(tableName, tableAlias); // 断言 assertEquals("u.dept_id IN (10, 20)", expression.toString()); + assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class)); } } @@ -200,12 +212,13 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest { String tableName = "t_user"; Alias tableAlias = new Alias("u"); // mock 方法(LoginUser) - LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)); + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L) + .setUserType(UserTypeEnum.ADMIN.getValue())); securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser); // mock 方法(DeptDataPermissionRespDTO) DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO() .setDeptIds(CollUtil.newLinkedHashSet(10L, 20L)).setSelf(true); - when(deptDataPermissionFrameworkService.getDeptDataPermission(same(loginUser))).thenReturn(deptDataPermission); + when(deptDataPermissionFrameworkService.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission); // 添加 user 字段配置 rule.addUserColumn("t_user", "id"); // 添加 dept 字段配置 @@ -215,6 +228,7 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest { Expression expression = rule.getExpression(tableName, tableAlias); // 断言 assertEquals("u.dept_id IN (10, 20) OR u.id = 1", expression.toString()); + assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class)); } } diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java index 84c7f94c4..c78148a46 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java @@ -50,17 +50,6 @@ public class LoginUser implements UserDetails { */ private Long tenantId; - // ========== UserTypeEnum.ADMIN 独有字段 ========== - // TODO 芋艿:可以通过定义一个 Map exts 的方式,去除管理员的字段。不过这样会导致系统比较复杂,所以暂时不去掉先; - /** - * 角色编号数组 - */ - private Set roleIds; - /** - * 部门编号 - */ - private Long deptId; - // ========== 上下文 ========== /** * 上下文字段,不进行持久化 diff --git a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java index 562c6ed9f..bbc1a9435 100644 --- a/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java +++ b/yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java @@ -11,7 +11,6 @@ import org.springframework.security.web.authentication.WebAuthenticationDetailsS import org.springframework.util.StringUtils; import javax.servlet.http.HttpServletRequest; -import java.util.Set; /** * 安全服务工具类 @@ -79,17 +78,6 @@ public class SecurityFrameworkUtils { return loginUser != null ? loginUser.getId() : null; } - /** - * 获得当前用户的角色编号数组 - * - * @return 角色编号数组 - */ - @Nullable - public static Set getLoginUserRoleIds() { - LoginUser loginUser = getLoginUser(); - return loginUser != null ? loginUser.getRoleIds() : null; - } - /** * 设置当前用户 * diff --git a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java index 5c2788df9..f82028f39 100644 --- a/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java +++ b/yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java @@ -84,7 +84,7 @@ public class MemberAuthServiceImpl implements MemberAuthService { @Override public String login(AppAuthLoginReqVO reqVO, String userIp, String userAgent) { // 使用手机 + 密码,进行登录。 - LoginUser loginUser = this.login0(reqVO.getMobile(), reqVO.getPassword()); + LoginUser loginUser = login0(reqVO.getMobile(), reqVO.getPassword()); // 缓存登录用户到 Redis 中,返回 Token 令牌 return createUserSessionAfterLoginSuccess(loginUser, LoginLogTypeEnum.LOGIN_USERNAME, userIp, userAgent); diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java index 6fbf2a21a..0e26674f8 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java @@ -26,12 +26,13 @@ import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import javax.validation.Valid; import java.util.List; +import java.util.Set; import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getUserAgent; import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserRoleIds; +import static java.util.Collections.singleton; @Api(tags = "管理后台 - 认证") @RestController @@ -69,12 +70,12 @@ public class AuthController { return null; } // 获得角色列表 - List roleList = roleService.getRolesFromCache(getLoginUserRoleIds()); + Set roleIds = permissionService.getUserRoleIds(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus())); + List roleList = roleService.getRolesFromCache(roleIds); // 获得菜单列表 - List menuList = permissionService.getRoleMenuListFromCache( - getLoginUserRoleIds(), // 注意,基于登录的角色,因为后续的权限判断也是基于它 + List menuList = permissionService.getRoleMenuListFromCache(roleIds, SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType(), MenuTypeEnum.BUTTON.getType()), - SetUtils.asSet(CommonStatusEnum.ENABLE.getStatus())); + singleton(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的 // 拼接结果返回 return success(AuthConvert.INSTANCE.convert(user, roleList, menuList)); } @@ -82,11 +83,12 @@ public class AuthController { @GetMapping("/list-menus") @ApiOperation("获得登录用户的菜单列表") public CommonResult> getMenus() { + // 获得角色列表 + Set roleIds = permissionService.getUserRoleIds(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus())); // 获得用户拥有的菜单列表 - List menuList = permissionService.getRoleMenuListFromCache( - getLoginUserRoleIds(), // 注意,基于登录的角色,因为后续的权限判断也是基于它 + List menuList = permissionService.getRoleMenuListFromCache(roleIds, SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType()), // 只要目录和菜单类型 - SetUtils.asSet(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的 + singleton(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的 // 转换成 Tree 结构返回 return success(AuthConvert.INSTANCE.buildMenuTree(menuList)); } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/UserSessionController.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/UserSessionController.java index 023532e08..9ce2edca9 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/UserSessionController.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/UserSessionController.java @@ -1,15 +1,16 @@ package cn.iocoder.yudao.module.system.controller.admin.auth; +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.module.system.controller.admin.auth.vo.session.UserSessionPageItemRespVO; import cn.iocoder.yudao.module.system.controller.admin.auth.vo.session.UserSessionPageReqVO; import cn.iocoder.yudao.module.system.convert.auth.UserSessionConvert; import cn.iocoder.yudao.module.system.dal.dataobject.auth.UserSessionDO; import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; -import cn.iocoder.yudao.module.system.service.auth.UserSessionService; import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; -import cn.iocoder.yudao.framework.common.pojo.CommonResult; -import cn.iocoder.yudao.framework.common.pojo.PageResult; -import cn.iocoder.yudao.framework.common.util.collection.MapUtils; +import cn.iocoder.yudao.module.system.service.auth.UserSessionService; import cn.iocoder.yudao.module.system.service.dept.DeptService; import cn.iocoder.yudao.module.system.service.user.AdminUserService; import io.swagger.annotations.Api; @@ -49,7 +50,8 @@ public class UserSessionController { // 获得拼接需要的数据 Map userMap = userService.getUserMap( - convertList(pageResult.getList(), UserSessionDO::getUserId)); + convertList(pageResult.getList(), UserSessionDO::getUserId, + session -> session.getUserType().equals(UserTypeEnum.ADMIN.getValue()))); Map deptMap = deptService.getDeptMap( convertList(userMap.values(), AdminUserDO::getDeptId)); // 拼接结果返回 diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java index 6476102bf..ebbfb6dfa 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java @@ -17,7 +17,6 @@ import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum; import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum; import cn.iocoder.yudao.module.system.service.common.CaptchaService; import cn.iocoder.yudao.module.system.service.logger.LoginLogService; -import cn.iocoder.yudao.module.system.service.permission.PermissionService; import cn.iocoder.yudao.module.system.service.social.SocialUserService; import cn.iocoder.yudao.module.system.service.user.AdminUserService; import lombok.extern.slf4j.Slf4j; @@ -36,12 +35,10 @@ import org.springframework.util.Assert; import javax.annotation.Resource; import javax.validation.Validator; import java.util.Objects; -import java.util.Set; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; -import static java.util.Collections.singleton; /** * Auth Service 实现类 @@ -60,8 +57,6 @@ public class AdminAuthServiceImpl implements AdminAuthService { @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") // UserService 存在重名 private AdminUserService userService; @Resource - private PermissionService permissionService; - @Resource private CaptchaService captchaService; @Resource private LoginLogService loginLogService; @@ -211,16 +206,6 @@ public class AdminAuthServiceImpl implements AdminAuthService { } } - /** - * 获得 User 拥有的角色编号数组 - * - * @param userId 用户编号 - * @return 角色编号数组 - */ - private Set getUserRoleIds(Long userId) { - return permissionService.getUserRoleIds(userId, singleton(CommonStatusEnum.ENABLE.getStatus())); - } - @Override public String socialQuickLogin(AuthSocialQuickLoginReqVO reqVO, String userIp, String userAgent) { // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号 @@ -318,17 +303,13 @@ public class AdminAuthServiceImpl implements AdminAuthService { } // 刷新 LoginUser 缓存 - LoginUser newLoginUser= this.buildLoginUser(user); + LoginUser newLoginUser= buildLoginUser(user); userSessionService.refreshUserSession(token, newLoginUser); return newLoginUser; } private LoginUser buildLoginUser(AdminUserDO user) { - LoginUser loginUser = AuthConvert.INSTANCE.convert(user); - // 补全字段 - loginUser.setDeptId(user.getDeptId()); - loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); - return loginUser; + return AuthConvert.INSTANCE.convert(user); } } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java index 08473d8cc..76e2055b3 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java @@ -3,12 +3,12 @@ package cn.iocoder.yudao.module.system.service.permission; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.util.ArrayUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils; +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission; import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO; -import cn.iocoder.yudao.framework.security.core.LoginUser; -import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore; import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO; @@ -22,6 +22,8 @@ import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleMapper; import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum; import cn.iocoder.yudao.module.system.mq.producer.permission.PermissionProducer; import cn.iocoder.yudao.module.system.service.dept.DeptService; +import cn.iocoder.yudao.module.system.service.user.AdminUserService; +import com.google.common.base.Suppliers; import com.google.common.collect.ImmutableMultimap; import com.google.common.collect.Multimap; import com.google.common.collect.Sets; @@ -36,6 +38,10 @@ import org.springframework.transaction.support.TransactionSynchronizationManager import javax.annotation.PostConstruct; import javax.annotation.Resource; import java.util.*; +import java.util.function.Supplier; + +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId; +import static java.util.Collections.singleton; /** * 权限 Service 实现类 @@ -46,11 +52,6 @@ import java.util.*; @Slf4j public class PermissionServiceImpl implements PermissionService { - /** - * LoginUser 的 Context 缓存 Key - */ - public static final String CONTEXT_KEY = PermissionServiceImpl.class.getSimpleName(); - /** * 定时执行 {@link #schedulePeriodicRefresh()} 的周期 * 因为已经通过 Redis Pub/Sub 机制,所以频率不需要高 @@ -93,6 +94,8 @@ public class PermissionServiceImpl implements PermissionService { private MenuService menuService; @Resource private DeptService deptService; + @Resource + private AdminUserService userService; @Resource private PermissionProducer permissionProducer; @@ -319,7 +322,7 @@ public class PermissionServiceImpl implements PermissionService { } // 获得当前登录的角色。如果为空,说明没有权限 - Set roleIds = SecurityFrameworkUtils.getLoginUserRoleIds(); + Set roleIds = getUserRoleIds(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus())); if (CollUtil.isEmpty(roleIds)) { return false; } @@ -354,7 +357,7 @@ public class PermissionServiceImpl implements PermissionService { } // 获得当前登录的角色。如果为空,说明没有权限 - Set roleIds = SecurityFrameworkUtils.getLoginUserRoleIds(); + Set roleIds = getUserRoleIds(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus())); if (CollUtil.isEmpty(roleIds)) { return false; } @@ -368,16 +371,18 @@ public class PermissionServiceImpl implements PermissionService { } @Override - public DeptDataPermissionRespDTO getDeptDataPermission(LoginUser loginUser) { - // 判断是否 context 已经缓存 - DeptDataPermissionRespDTO result = loginUser.getContext(CONTEXT_KEY, DeptDataPermissionRespDTO.class); - if (result != null) { + @DataPermission(enable = false) // 关闭数据权限,不然就会出现递归获取数据权限的问题 + public DeptDataPermissionRespDTO getDeptDataPermission(Long userId) { + DeptDataPermissionRespDTO result = new DeptDataPermissionRespDTO(); + // 获得用户的角色 + Set roleIds = getUserRoleIds(userId, singleton(CommonStatusEnum.ENABLE.getStatus())); + if (CollUtil.isEmpty(roleIds)) { return result; } - - // 创建 DeptDataPermissionRespDTO 对象 - result = new DeptDataPermissionRespDTO(); - List roles = roleService.getRolesFromCache(loginUser.getRoleIds()); + List roles = roleService.getRolesFromCache(roleIds); + // 获得用户的部门编号的缓存,通过 Guava 的 Suppliers 惰性求值,即有且仅有第一次发起 DB 的查询 + Supplier userDeptIdCache = Suppliers.memoize(() -> userService.getUser(userId).getDeptId()); + // 遍历每个角色,计算 for (RoleDO role : roles) { // 为空时,跳过 if (role.getDataScope() == null) { @@ -393,20 +398,20 @@ public class PermissionServiceImpl implements PermissionService { CollUtil.addAll(result.getDeptIds(), role.getDataScopeDeptIds()); // 自定义可见部门时,保证可以看到自己所在的部门。否则,一些场景下可能会有问题。 // 例如说,登录时,基于 t_user 的 username 查询会可能被 dept_id 过滤掉 - CollUtil.addAll(result.getDeptIds(), loginUser.getDeptId()); + CollUtil.addAll(result.getDeptIds(), userDeptIdCache.get()); continue; } // 情况三,DEPT_ONLY if (Objects.equals(role.getDataScope(), DataScopeEnum.DEPT_ONLY.getScope())) { - CollectionUtils.addIfNotNull(result.getDeptIds(), loginUser.getDeptId()); + CollectionUtils.addIfNotNull(result.getDeptIds(), userDeptIdCache.get()); continue; } // 情况四,DEPT_DEPT_AND_CHILD if (Objects.equals(role.getDataScope(), DataScopeEnum.DEPT_AND_CHILD.getScope())) { - List depts = deptService.getDeptsByParentIdFromCache(loginUser.getDeptId(), true); + List depts = deptService.getDeptsByParentIdFromCache(userDeptIdCache.get(), true); CollUtil.addAll(result.getDeptIds(), CollectionUtils.convertList(depts, DeptDO::getId)); - //添加本身部门id - CollUtil.addAll(result.getDeptIds(), loginUser.getDeptId()); + // 添加本身部门编号 + CollUtil.addAll(result.getDeptIds(), userDeptIdCache.get()); continue; } // 情况五,SELF @@ -415,11 +420,8 @@ public class PermissionServiceImpl implements PermissionService { continue; } // 未知情况,error log 即可 - log.error("[getDeptDataPermission][LoginUser({}) role({}) 无法处理]", loginUser.getId(), JsonUtils.toJsonString(result)); + log.error("[getDeptDataPermission][LoginUser({}) role({}) 无法处理]", userId, JsonUtils.toJsonString(result)); } - - // 添加到缓存,并返回 - loginUser.setContext(CONTEXT_KEY, result); return result; } diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java index e0038ffcd..160ffe824 100755 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java @@ -81,6 +81,7 @@ public class TenantServiceImpl implements TenantService { @Getter private volatile Date maxUpdateTime; + @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") @Autowired(required = false) // 由于 yudao.tenant.enable 配置项,可以关闭多租户的功能,所以这里只能不强制注入 private TenantProperties tenantProperties; diff --git a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java index 44934c6fa..9208b2e69 100644 --- a/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java +++ b/yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java @@ -25,6 +25,7 @@ import cn.iocoder.yudao.module.system.service.tenant.TenantService; import com.google.common.annotations.VisibleForTesting; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Lazy; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -61,6 +62,7 @@ public class AdminUserServiceImpl implements AdminUserService { @Resource private PasswordEncoder passwordEncoder; @Resource + @Lazy // 延迟,避免循环依赖报错 private TenantService tenantService; @Resource diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AuthServiceImplTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AuthServiceImplTest.java index 47b767eb5..0cb376668 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AuthServiceImplTest.java +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AuthServiceImplTest.java @@ -1,6 +1,5 @@ package cn.iocoder.yudao.module.system.service.auth; -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; import cn.iocoder.yudao.framework.security.core.LoginUser; import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.framework.test.core.util.AssertUtils; @@ -12,7 +11,6 @@ import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum; import cn.iocoder.yudao.module.system.service.common.CaptchaService; import cn.iocoder.yudao.module.system.service.dept.PostService; import cn.iocoder.yudao.module.system.service.logger.LoginLogService; -import cn.iocoder.yudao.module.system.service.permission.PermissionService; import cn.iocoder.yudao.module.system.service.social.SocialUserService; import cn.iocoder.yudao.module.system.service.user.AdminUserService; import org.junit.jupiter.api.BeforeEach; @@ -34,7 +32,6 @@ import java.util.Set; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*; import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*; -import static java.util.Collections.singleton; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.eq; @@ -49,8 +46,6 @@ public class AuthServiceImplTest extends BaseDbUnitTest { @MockBean private AdminUserService userService; @MockBean - private PermissionService permissionService; - @MockBean private AuthenticationManager authenticationManager; @MockBean private Authentication authentication; @@ -108,16 +103,11 @@ public class AuthServiceImplTest extends BaseDbUnitTest { // mock 方法 01 AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setId(userId)); when(userService.getUser(eq(userId))).thenReturn(user); - // mock 方法 02 - Set roleIds = randomSet(Long.class); - when(permissionService.getUserRoleIds(eq(userId), eq(singleton(CommonStatusEnum.ENABLE.getStatus())))) - .thenReturn(roleIds); // 调用 LoginUser loginUser = authService.mockLogin(userId); // 断言 AssertUtils.assertPojoEquals(user, loginUser, "updateTime"); - assertEquals(roleIds, loginUser.getRoleIds()); } @Test @@ -247,15 +237,10 @@ public class AuthServiceImplTest extends BaseDbUnitTest { // mock authentication Long userId = randomLongId(); Set userRoleIds = randomSet(Long.class); - LoginUser loginUser = randomPojo(LoginUser.class, o -> { - o.setId(userId); - o.setRoleIds(userRoleIds); - }); + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(userId)); when(authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(reqVO.getUsername(), reqVO.getPassword()))) .thenReturn(authentication); when(authentication.getPrincipal()).thenReturn(loginUser); - // mock 获得 User 拥有的角色编号数组 - when(permissionService.getUserRoleIds(userId, singleton(CommonStatusEnum.ENABLE.getStatus()))).thenReturn(userRoleIds); // mock 缓存登录用户到 Redis String token = randomString(); when(userSessionService.createUserSession(loginUser, userIp, userAgent)).thenReturn(token); diff --git a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceTest.java b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceTest.java index 7ac339f54..12fddf38a 100644 --- a/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceTest.java +++ b/yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceTest.java @@ -1,20 +1,22 @@ package cn.iocoder.yudao.module.system.service.permission; import cn.hutool.core.collection.CollUtil; +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; +import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO; +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleMenuDO; import cn.iocoder.yudao.module.system.dal.dataobject.permission.UserRoleDO; +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMenuBatchInsertMapper; import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMenuMapper; import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleBatchInsertMapper; import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleMapper; +import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum; import cn.iocoder.yudao.module.system.mq.producer.permission.PermissionProducer; import cn.iocoder.yudao.module.system.service.dept.DeptService; -import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO; -import cn.iocoder.yudao.framework.security.core.LoginUser; -import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum; -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest; +import cn.iocoder.yudao.module.system.service.user.AdminUserService; import org.junit.jupiter.api.Test; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Import; @@ -25,10 +27,10 @@ import java.util.List; import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId; import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo; +import static java.util.Collections.singleton; import static java.util.Collections.singletonList; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -54,6 +56,9 @@ public class PermissionServiceTest extends BaseDbUnitTest { private MenuService menuService; @MockBean private DeptService deptService; + @MockBean + private AdminUserService userService; + @MockBean private PermissionProducer permissionProducer; @@ -124,112 +129,119 @@ public class PermissionServiceTest extends BaseDbUnitTest { assertPojoEquals(dbUserRoles.get(0), userRoleDO02); } - @Test // 测试从 context 获取的场景 - public void testGetDeptDataPermission_fromContext() { - // 准备参数 - LoginUser loginUser = randomPojo(LoginUser.class); - // mock 方法 - DeptDataPermissionRespDTO respDTO = new DeptDataPermissionRespDTO(); - loginUser.setContext(PermissionServiceImpl.CONTEXT_KEY, respDTO); - - // 调用 - DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(loginUser); - // 断言 - assertSame(respDTO, result); - } - @Test public void testGetDeptDataPermission_All() { // 准备参数 - LoginUser loginUser = randomPojo(LoginUser.class); - // mock 方法 - RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.ALL.getScope())); - when(roleService.getRolesFromCache(same(loginUser.getRoleIds()))).thenReturn(singletonList(roleDO)); + Long userId = 1L; + // mock 用户的角色编号 + userRoleMapper.insert(new UserRoleDO().setUserId(userId).setRoleId(2L)); + // mock 获得用户的角色 + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.ALL.getScope()) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + when(roleService.getRolesFromCache(eq(singleton(2L)))).thenReturn(singletonList(roleDO)); + when(roleService.getRoleFromCache(eq(2L))).thenReturn(roleDO); // 调用 - DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(loginUser); + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); // 断言 assertTrue(result.getAll()); assertFalse(result.getSelf()); assertTrue(CollUtil.isEmpty(result.getDeptIds())); - assertSame(result, loginUser.getContext(PermissionServiceImpl.CONTEXT_KEY, DeptDataPermissionRespDTO.class)); } @Test public void testGetDeptDataPermission_DeptCustom() { // 准备参数 - LoginUser loginUser = randomPojo(LoginUser.class); - // mock 方法 - RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_CUSTOM.getScope())); - when(roleService.getRolesFromCache(same(loginUser.getRoleIds()))).thenReturn(singletonList(roleDO)); + Long userId = 1L; + // mock 用户的角色编号 + userRoleMapper.insert(new UserRoleDO().setUserId(userId).setRoleId(2L)); + // mock 获得用户的角色 + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_CUSTOM.getScope()) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + when(roleService.getRolesFromCache(eq(singleton(2L)))).thenReturn(singletonList(roleDO)); + when(roleService.getRoleFromCache(eq(2L))).thenReturn(roleDO); + // mock 部门的返回 + when(userService.getUser(eq(1L))).thenReturn(new AdminUserDO().setDeptId(3L), null, null); // 最后返回 null 的目的,看看会不会重复调用 // 调用 - DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(loginUser); + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(1L); // 断言 assertFalse(result.getAll()); assertFalse(result.getSelf()); assertEquals(roleDO.getDataScopeDeptIds().size() + 1, result.getDeptIds().size()); assertTrue(CollUtil.containsAll(result.getDeptIds(), roleDO.getDataScopeDeptIds())); - assertTrue(CollUtil.contains(result.getDeptIds(), loginUser.getDeptId())); - assertSame(result, loginUser.getContext(PermissionServiceImpl.CONTEXT_KEY, DeptDataPermissionRespDTO.class)); + assertTrue(CollUtil.contains(result.getDeptIds(), 3L)); } @Test public void testGetDeptDataPermission_DeptOnly() { // 准备参数 - LoginUser loginUser = randomPojo(LoginUser.class); - // mock 方法 - RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_ONLY.getScope())); - when(roleService.getRolesFromCache(same(loginUser.getRoleIds()))).thenReturn(singletonList(roleDO)); + Long userId = 1L; + // mock 用户的角色编号 + userRoleMapper.insert(new UserRoleDO().setUserId(userId).setRoleId(2L)); + // mock 获得用户的角色 + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_ONLY.getScope()) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + when(roleService.getRolesFromCache(eq(singleton(2L)))).thenReturn(singletonList(roleDO)); + when(roleService.getRoleFromCache(eq(2L))).thenReturn(roleDO); + // mock 部门的返回 + when(userService.getUser(eq(1L))).thenReturn(new AdminUserDO().setDeptId(3L), null, null); // 最后返回 null 的目的,看看会不会重复调用 // 调用 - DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(loginUser); + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(1L); // 断言 assertFalse(result.getAll()); assertFalse(result.getSelf()); assertEquals(1, result.getDeptIds().size()); - assertTrue(CollUtil.contains(result.getDeptIds(), loginUser.getDeptId())); - assertSame(result, loginUser.getContext(PermissionServiceImpl.CONTEXT_KEY, DeptDataPermissionRespDTO.class)); + assertTrue(CollUtil.contains(result.getDeptIds(), 3L)); } @Test public void testGetDeptDataPermission_DeptAndChild() { // 准备参数 - LoginUser loginUser = randomPojo(LoginUser.class); - // mock 方法(角色) - RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_AND_CHILD.getScope())); - when(roleService.getRolesFromCache(same(loginUser.getRoleIds()))).thenReturn(singletonList(roleDO)); + Long userId = 1L; + // mock 用户的角色编号 + userRoleMapper.insert(new UserRoleDO().setUserId(userId).setRoleId(2L)); + // mock 获得用户的角色 + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_AND_CHILD.getScope()) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + when(roleService.getRolesFromCache(eq(singleton(2L)))).thenReturn(singletonList(roleDO)); + when(roleService.getRoleFromCache(eq(2L))).thenReturn(roleDO); + // mock 部门的返回 + when(userService.getUser(eq(1L))).thenReturn(new AdminUserDO().setDeptId(3L), null, null); // 最后返回 null 的目的,看看会不会重复调用 // mock 方法(部门) DeptDO deptDO = randomPojo(DeptDO.class); - when(deptService.getDeptsByParentIdFromCache(eq(loginUser.getDeptId()), eq(true))) + when(deptService.getDeptsByParentIdFromCache(eq(3L), eq(true))) .thenReturn(singletonList(deptDO)); // 调用 - DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(loginUser); + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); // 断言 assertFalse(result.getAll()); assertFalse(result.getSelf()); assertEquals(2, result.getDeptIds().size()); assertTrue(CollUtil.contains(result.getDeptIds(), deptDO.getId())); - assertTrue(CollUtil.contains(result.getDeptIds(), loginUser.getDeptId())); - assertSame(result, loginUser.getContext(PermissionServiceImpl.CONTEXT_KEY, DeptDataPermissionRespDTO.class)); + assertTrue(CollUtil.contains(result.getDeptIds(), 3L)); } @Test public void testGetDeptDataPermission_Self() { // 准备参数 - LoginUser loginUser = randomPojo(LoginUser.class); - // mock 方法 - RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.SELF.getScope())); - when(roleService.getRolesFromCache(same(loginUser.getRoleIds()))).thenReturn(singletonList(roleDO)); + Long userId = 1L; + // mock 用户的角色编号 + userRoleMapper.insert(new UserRoleDO().setUserId(userId).setRoleId(2L)); + // mock 获得用户的角色 + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.SELF.getScope()) + .setStatus(CommonStatusEnum.ENABLE.getStatus())); + when(roleService.getRolesFromCache(eq(singleton(2L)))).thenReturn(singletonList(roleDO)); + when(roleService.getRoleFromCache(eq(2L))).thenReturn(roleDO); // 调用 - DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(loginUser); + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId); // 断言 assertFalse(result.getAll()); assertTrue(result.getSelf()); assertTrue(CollUtil.isEmpty(result.getDeptIds())); - assertSame(result, loginUser.getContext(PermissionServiceImpl.CONTEXT_KEY, DeptDataPermissionRespDTO.class)); } }