Переглянути джерело

去除 LoginUser 的 roleIds、deptId 字段,简化

YunaiV 3 роки тому
батько
коміт
8737674d74
16 змінених файлів з 179 додано та 189 видалено
  1. 0 7
      yudao-dependencies/pom.xml
  2. 7 0
      yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java
  3. 26 13
      yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/rule/DeptDataPermissionRule.java
  4. 2 3
      yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/service/DeptDataPermissionFrameworkService.java
  5. 27 13
      yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/test/java/cn/iocoder/yudao/framework/datapermission/core/dept/rule/DeptDataPermissionRuleTest.java
  6. 0 11
      yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java
  7. 0 12
      yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/util/SecurityFrameworkUtils.java
  8. 1 1
      yudao-module-member/yudao-module-member-biz/src/main/java/cn/iocoder/yudao/module/member/service/auth/MemberAuthServiceImpl.java
  9. 10 8
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/AuthController.java
  10. 7 5
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/UserSessionController.java
  11. 2 21
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/auth/AdminAuthServiceImpl.java
  12. 28 26
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceImpl.java
  13. 1 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/tenant/TenantServiceImpl.java
  14. 2 0
      yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/service/user/AdminUserServiceImpl.java
  15. 1 16
      yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AuthServiceImplTest.java
  16. 65 53
      yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceTest.java

+ 0 - 7
yudao-dependencies/pom.xml

@@ -22,7 +22,6 @@
         <swagger-annotations.version>1.5.22</swagger-annotations.version>
         <servlet.versoin>2.5</servlet.versoin>
         <!-- DB 相关 -->
-        <mysql.version>5.1.46</mysql.version>
         <druid.version>1.2.8</druid.version>
         <mybatis-plus.version>3.4.3.4</mybatis-plus.version>
         <mybatis-plus-generator.version>3.5.2</mybatis-plus-generator.version>
@@ -76,12 +75,6 @@
                 <version>${spring.boot.version}</version>
                 <type>pom</type>
                 <scope>import</scope>
-                <exclusions>
-                    <exclusion>
-                        <groupId>mysql</groupId>
-                        <artifactId>mysql-connector-java</artifactId>
-                    </exclusion>
-                </exclusions>
             </dependency>
 
             <!-- 业务组件 -->

+ 7 - 0
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 <T, U> List<U> convertList(Collection<T> from, Function<T, U> func, Predicate<T> filter) {
+        if (CollUtil.isEmpty(from)) {
+            return new ArrayList<>();
+        }
+        return from.stream().filter(filter).map(func).filter(Objects::nonNull).collect(Collectors.toList());
+    }
+
     public static <T, U> Set<U> convertSet(Collection<T> from, Function<T, U> func) {
         if (CollUtil.isEmpty(from)) {
             return new HashSet<>();

+ 26 - 13
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({}) 构建的条件为空]",

+ 2 - 3
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);
 
 }

+ 27 - 13
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));
         }
     }
 

+ 0 - 11
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<String, String> exts 的方式,去除管理员的字段。不过这样会导致系统比较复杂,所以暂时不去掉先;
-    /**
-     * 角色编号数组
-     */
-    private Set<Long> roleIds;
-    /**
-     * 部门编号
-     */
-    private Long deptId;
-
     // ========== 上下文 ==========
     /**
      * 上下文字段,不进行持久化

+ 0 - 12
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;
 
 /**
  * 安全服务工具类
@@ -80,17 +79,6 @@ public class SecurityFrameworkUtils {
     }
 
     /**
-     * 获得当前用户的角色编号数组
-     *
-     * @return 角色编号数组
-     */
-    @Nullable
-    public static Set<Long> getLoginUserRoleIds() {
-        LoginUser loginUser = getLoginUser();
-        return loginUser != null ? loginUser.getRoleIds() : null;
-    }
-
-    /**
      * 设置当前用户
      *
      * @param loginUser 登录用户

+ 1 - 1
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);

+ 10 - 8
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<RoleDO> roleList = roleService.getRolesFromCache(getLoginUserRoleIds());
+        Set<Long> roleIds = permissionService.getUserRoleIds(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus()));
+        List<RoleDO> roleList = roleService.getRolesFromCache(roleIds);
         // 获得菜单列表
-        List<MenuDO> menuList = permissionService.getRoleMenuListFromCache(
-                getLoginUserRoleIds(), // 注意,基于登录的角色,因为后续的权限判断也是基于它
+        List<MenuDO> 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<List<AuthMenuRespVO>> getMenus() {
+        // 获得角色列表
+        Set<Long> roleIds = permissionService.getUserRoleIds(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus()));
         // 获得用户拥有的菜单列表
-        List<MenuDO> menuList = permissionService.getRoleMenuListFromCache(
-                getLoginUserRoleIds(), // 注意,基于登录的角色,因为后续的权限判断也是基于它
+        List<MenuDO> 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));
     }

+ 7 - 5
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<Long, AdminUserDO> userMap = userService.getUserMap(
-                convertList(pageResult.getList(), UserSessionDO::getUserId));
+                convertList(pageResult.getList(), UserSessionDO::getUserId,
+                        session -> session.getUserType().equals(UserTypeEnum.ADMIN.getValue())));
         Map<Long, DeptDO> deptMap = deptService.getDeptMap(
                 convertList(userMap.values(), AdminUserDO::getDeptId));
         // 拼接结果返回

+ 2 - 21
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<Long> 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);
     }
 
 }

+ 28 - 26
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 实现类
@@ -47,11 +53,6 @@ import java.util.*;
 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<Long> roleIds = SecurityFrameworkUtils.getLoginUserRoleIds();
+        Set<Long> roleIds = getUserRoleIds(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus()));
         if (CollUtil.isEmpty(roleIds)) {
             return false;
         }
@@ -354,7 +357,7 @@ public class PermissionServiceImpl implements PermissionService {
         }
 
         // 获得当前登录的角色。如果为空,说明没有权限
-        Set<Long> roleIds = SecurityFrameworkUtils.getLoginUserRoleIds();
+        Set<Long> 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<Long> roleIds = getUserRoleIds(userId, singleton(CommonStatusEnum.ENABLE.getStatus()));
+        if (CollUtil.isEmpty(roleIds)) {
             return result;
         }
-
-        // 创建 DeptDataPermissionRespDTO 对象
-        result = new DeptDataPermissionRespDTO();
-        List<RoleDO> roles = roleService.getRolesFromCache(loginUser.getRoleIds());
+        List<RoleDO> roles = roleService.getRolesFromCache(roleIds);
+        // 获得用户的部门编号的缓存,通过 Guava 的 Suppliers 惰性求值,即有且仅有第一次发起 DB 的查询
+        Supplier<Long> 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<DeptDO> depts = deptService.getDeptsByParentIdFromCache(loginUser.getDeptId(), true);
+                List<DeptDO> 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;
     }
 

+ 1 - 0
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;
 

+ 2 - 0
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

+ 1 - 16
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<Long> 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<Long> 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);

+ 65 - 53
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;
 
@@ -55,6 +57,9 @@ public class PermissionServiceTest extends BaseDbUnitTest {
     @MockBean
     private DeptService deptService;
     @MockBean
+    private AdminUserService userService;
+
+    @MockBean
     private PermissionProducer permissionProducer;
 
     @Test
@@ -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));
     }
 
 }