Commit 8737674d743ea2bcfdb0a50a0d7f007c58753884

Authored by YunaiV
1 parent d8a24262

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

Showing 16 changed files with 179 additions and 189 deletions
yudao-dependencies/pom.xml
... ... @@ -22,7 +22,6 @@
22 22 <swagger-annotations.version>1.5.22</swagger-annotations.version>
23 23 <servlet.versoin>2.5</servlet.versoin>
24 24 <!-- DB 相关 -->
25   - <mysql.version>5.1.46</mysql.version>
26 25 <druid.version>1.2.8</druid.version>
27 26 <mybatis-plus.version>3.4.3.4</mybatis-plus.version>
28 27 <mybatis-plus-generator.version>3.5.2</mybatis-plus-generator.version>
... ... @@ -76,12 +75,6 @@
76 75 <version>${spring.boot.version}</version>
77 76 <type>pom</type>
78 77 <scope>import</scope>
79   - <exclusions>
80   - <exclusion>
81   - <groupId>mysql</groupId>
82   - <artifactId>mysql-connector-java</artifactId>
83   - </exclusion>
84   - </exclusions>
85 78 </dependency>
86 79  
87 80 <!-- 业务组件 -->
... ...
yudao-framework/yudao-common/src/main/java/cn/iocoder/yudao/framework/common/util/collection/CollectionUtils.java
... ... @@ -54,6 +54,13 @@ public class CollectionUtils {
54 54 return from.stream().map(func).filter(Objects::nonNull).collect(Collectors.toList());
55 55 }
56 56  
  57 + public static <T, U> List<U> convertList(Collection<T> from, Function<T, U> func, Predicate<T> filter) {
  58 + if (CollUtil.isEmpty(from)) {
  59 + return new ArrayList<>();
  60 + }
  61 + return from.stream().filter(filter).map(func).filter(Objects::nonNull).collect(Collectors.toList());
  62 + }
  63 +
57 64 public static <T, U> Set<U> convertSet(Collection<T> from, Function<T, U> func) {
58 65 if (CollUtil.isEmpty(from)) {
59 66 return new HashSet<>();
... ...
yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/rule/DeptDataPermissionRule.java
1 1 package cn.iocoder.yudao.framework.datapermission.core.dept.rule;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
  4 +import cn.hutool.core.util.ObjectUtil;
4 5 import cn.hutool.core.util.StrUtil;
5   -import cn.iocoder.yudao.framework.datapermission.core.dept.service.DeptDataPermissionFrameworkService;
6   -import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO;
  6 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
7 7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
8 8 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
  9 +import cn.iocoder.yudao.framework.datapermission.core.dept.service.DeptDataPermissionFrameworkService;
  10 +import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO;
9 11 import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule;
10 12 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
11 13 import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
... ... @@ -13,7 +15,6 @@ import cn.iocoder.yudao.framework.security.core.LoginUser;
13 15 import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
14 16 import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
15 17 import lombok.AllArgsConstructor;
16   -import lombok.Getter;
17 18 import lombok.extern.slf4j.Slf4j;
18 19 import net.sf.jsqlparser.expression.Alias;
19 20 import net.sf.jsqlparser.expression.Expression;
... ... @@ -24,10 +25,7 @@ import net.sf.jsqlparser.expression.operators.relational.EqualsTo;
24 25 import net.sf.jsqlparser.expression.operators.relational.ExpressionList;
25 26 import net.sf.jsqlparser.expression.operators.relational.InExpression;
26 27  
27   -import java.util.HashMap;
28   -import java.util.HashSet;
29   -import java.util.Map;
30   -import java.util.Set;
  28 +import java.util.*;
31 29  
32 30 /**
33 31 * 基于部门的 {@link DataPermissionRule} 数据权限规则实现
... ... @@ -50,6 +48,11 @@ import java.util.Set;
50 48 @Slf4j
51 49 public class DeptDataPermissionRule implements DataPermissionRule {
52 50  
  51 + /**
  52 + * LoginUser 的 Context 缓存 Key
  53 + */
  54 + protected static final String CONTEXT_KEY = DeptDataPermissionRule.class.getSimpleName();
  55 +
53 56 private static final String DEPT_COLUMN_NAME = "dept_id";
54 57 private static final String USER_COLUMN_NAME = "user_id";
55 58  
... ... @@ -90,13 +93,23 @@ public class DeptDataPermissionRule implements DataPermissionRule {
90 93 if (loginUser == null) {
91 94 return null;
92 95 }
  96 + // 只有管理员类型的用户,才进行数据权限的处理
  97 + if (ObjectUtil.notEqual(loginUser.getUserType(), UserTypeEnum.ADMIN.getValue())) {
  98 + return null;
  99 + }
93 100  
94 101 // 获得数据权限
95   - DeptDataPermissionRespDTO deptDataPermission = deptDataPermissionService.getDeptDataPermission(loginUser);
  102 + DeptDataPermissionRespDTO deptDataPermission = loginUser.getContext(CONTEXT_KEY, DeptDataPermissionRespDTO.class);
  103 + // 从上下文中拿不到,则调用逻辑进行获取
96 104 if (deptDataPermission == null) {
97   - log.error("[getExpression][LoginUser({}) 获取数据权限为 null]", JsonUtils.toJsonString(loginUser));
98   - throw new NullPointerException(String.format("LoginUser(%d) Table(%s/%s) 未返回数据权限",
99   - loginUser.getId(), tableName, tableAlias.getName()));
  105 + deptDataPermission = deptDataPermissionService.getDeptDataPermission(loginUser.getId());
  106 + if (deptDataPermission == null) {
  107 + log.error("[getExpression][LoginUser({}) 获取数据权限为 null]", JsonUtils.toJsonString(loginUser));
  108 + throw new NullPointerException(String.format("LoginUser(%d) Table(%s/%s) 未返回数据权限",
  109 + loginUser.getId(), tableName, tableAlias.getName()));
  110 + }
  111 + // 添加到上下文中,避免重复计算
  112 + loginUser.setContext(CONTEXT_KEY, deptDataPermission);
100 113 }
101 114  
102 115 // 情况一,如果是 ALL 可查看全部,则无需拼接条件
... ... @@ -111,8 +124,8 @@ public class DeptDataPermissionRule implements DataPermissionRule {
111 124 }
112 125  
113 126 // 情况三,拼接 Dept 和 User 的条件,最后组合
114   - Expression deptExpression = this.buildDeptExpression(tableName,tableAlias, deptDataPermission.getDeptIds());
115   - Expression userExpression = this.buildUserExpression(tableName, tableAlias, deptDataPermission.getSelf(), loginUser.getId());
  127 + Expression deptExpression = buildDeptExpression(tableName,tableAlias, deptDataPermission.getDeptIds());
  128 + Expression userExpression = buildUserExpression(tableName, tableAlias, deptDataPermission.getSelf(), loginUser.getId());
116 129 if (deptExpression == null && userExpression == null) {
117 130 // TODO 芋艿:获得不到条件的时候,暂时不抛出异常,而是不返回数据
118 131 log.warn("[getExpression][LoginUser({}) Table({}/{}) DeptDataPermission({}) 构建的条件为空]",
... ...
yudao-framework/yudao-spring-boot-starter-biz-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/core/dept/service/DeptDataPermissionFrameworkService.java
1 1 package cn.iocoder.yudao.framework.datapermission.core.dept.service;
2 2  
3 3 import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO;
4   -import cn.iocoder.yudao.framework.security.core.LoginUser;
5 4  
6 5 /**
7 6 * 基于部门的数据权限 Framework Service 接口
... ... @@ -14,9 +13,9 @@ public interface DeptDataPermissionFrameworkService {
14 13 /**
15 14 * 获得登陆用户的部门数据权限
16 15 *
17   - * @param loginUser 登陆用户
  16 + * @param userId 用户编号
18 17 * @return 部门数据权限
19 18 */
20   - DeptDataPermissionRespDTO getDeptDataPermission(LoginUser loginUser);
  19 + DeptDataPermissionRespDTO getDeptDataPermission(Long userId);
21 20  
22 21 }
... ...
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;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.util.ReflectUtil;
  5 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
5 6 import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
6 7 import cn.iocoder.yudao.framework.datapermission.core.dept.service.DeptDataPermissionFrameworkService;
7 8 import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO;
... ... @@ -69,7 +70,8 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
69 70 String tableName = "t_user";
70 71 Alias tableAlias = new Alias("u");
71 72 // mock 方法
72   - LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L));
  73 + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)
  74 + .setUserType(UserTypeEnum.ADMIN.getValue()));
73 75 securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
74 76  
75 77 // 调用
... ... @@ -88,16 +90,18 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
88 90 String tableName = "t_user";
89 91 Alias tableAlias = new Alias("u");
90 92 // mock 方法(LoginUser)
91   - LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L));
  93 + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)
  94 + .setUserType(UserTypeEnum.ADMIN.getValue()));
92 95 securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
93 96 // mock 方法(DeptDataPermissionRespDTO)
94 97 DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO().setAll(true);
95   - when(deptDataPermissionFrameworkService.getDeptDataPermission(same(loginUser))).thenReturn(deptDataPermission);
  98 + when(deptDataPermissionFrameworkService.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission);
96 99  
97 100 // 调用
98 101 Expression expression = rule.getExpression(tableName, tableAlias);
99 102 // 断言
100 103 assertNull(expression);
  104 + assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class));
101 105 }
102 106 }
103 107  
... ... @@ -109,16 +113,18 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
109 113 String tableName = "t_user";
110 114 Alias tableAlias = new Alias("u");
111 115 // mock 方法(LoginUser)
112   - LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L));
  116 + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)
  117 + .setUserType(UserTypeEnum.ADMIN.getValue()));
113 118 securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
114 119 // mock 方法(DeptDataPermissionRespDTO)
115 120 DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO();
116   - when(deptDataPermissionFrameworkService.getDeptDataPermission(same(loginUser))).thenReturn(deptDataPermission);
  121 + when(deptDataPermissionFrameworkService.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission);
117 122  
118 123 // 调用
119 124 Expression expression = rule.getExpression(tableName, tableAlias);
120 125 // 断言
121 126 assertEquals("null = null", expression.toString());
  127 + assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class));
122 128 }
123 129 }
124 130  
... ... @@ -130,17 +136,19 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
130 136 String tableName = "t_user";
131 137 Alias tableAlias = new Alias("u");
132 138 // mock 方法(LoginUser)
133   - LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L));
  139 + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)
  140 + .setUserType(UserTypeEnum.ADMIN.getValue()));
134 141 securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
135 142 // mock 方法(DeptDataPermissionRespDTO)
136 143 DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO()
137 144 .setDeptIds(SetUtils.asSet(10L, 20L)).setSelf(true);
138   - when(deptDataPermissionFrameworkService.getDeptDataPermission(same(loginUser))).thenReturn(deptDataPermission);
  145 + when(deptDataPermissionFrameworkService.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission);
139 146  
140 147 // 调用
141 148 Expression expression = rule.getExpression(tableName, tableAlias);
142 149 // 断言
143 150 assertSame(EXPRESSION_NULL, expression);
  151 + assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class));
144 152 }
145 153 }
146 154  
... ... @@ -152,12 +160,13 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
152 160 String tableName = "t_user";
153 161 Alias tableAlias = new Alias("u");
154 162 // mock 方法(LoginUser)
155   - LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L));
  163 + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)
  164 + .setUserType(UserTypeEnum.ADMIN.getValue()));
156 165 securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
157 166 // mock 方法(DeptDataPermissionRespDTO)
158 167 DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO()
159 168 .setSelf(true);
160   - when(deptDataPermissionFrameworkService.getDeptDataPermission(same(loginUser))).thenReturn(deptDataPermission);
  169 + when(deptDataPermissionFrameworkService.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission);
161 170 // 添加 user 字段配置
162 171 rule.addUserColumn("t_user", "id");
163 172  
... ... @@ -165,6 +174,7 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
165 174 Expression expression = rule.getExpression(tableName, tableAlias);
166 175 // 断言
167 176 assertEquals("u.id = 1", expression.toString());
  177 + assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class));
168 178 }
169 179 }
170 180  
... ... @@ -176,12 +186,13 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
176 186 String tableName = "t_user";
177 187 Alias tableAlias = new Alias("u");
178 188 // mock 方法(LoginUser)
179   - LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L));
  189 + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)
  190 + .setUserType(UserTypeEnum.ADMIN.getValue()));
180 191 securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
181 192 // mock 方法(DeptDataPermissionRespDTO)
182 193 DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO()
183 194 .setDeptIds(CollUtil.newLinkedHashSet(10L, 20L));
184   - when(deptDataPermissionFrameworkService.getDeptDataPermission(same(loginUser))).thenReturn(deptDataPermission);
  195 + when(deptDataPermissionFrameworkService.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission);
185 196 // 添加 dept 字段配置
186 197 rule.addDeptColumn("t_user", "dept_id");
187 198  
... ... @@ -189,6 +200,7 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
189 200 Expression expression = rule.getExpression(tableName, tableAlias);
190 201 // 断言
191 202 assertEquals("u.dept_id IN (10, 20)", expression.toString());
  203 + assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class));
192 204 }
193 205 }
194 206  
... ... @@ -200,12 +212,13 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
200 212 String tableName = "t_user";
201 213 Alias tableAlias = new Alias("u");
202 214 // mock 方法(LoginUser)
203   - LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L));
  215 + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(1L)
  216 + .setUserType(UserTypeEnum.ADMIN.getValue()));
204 217 securityFrameworkUtilsMock.when(SecurityFrameworkUtils::getLoginUser).thenReturn(loginUser);
205 218 // mock 方法(DeptDataPermissionRespDTO)
206 219 DeptDataPermissionRespDTO deptDataPermission = new DeptDataPermissionRespDTO()
207 220 .setDeptIds(CollUtil.newLinkedHashSet(10L, 20L)).setSelf(true);
208   - when(deptDataPermissionFrameworkService.getDeptDataPermission(same(loginUser))).thenReturn(deptDataPermission);
  221 + when(deptDataPermissionFrameworkService.getDeptDataPermission(same(1L))).thenReturn(deptDataPermission);
209 222 // 添加 user 字段配置
210 223 rule.addUserColumn("t_user", "id");
211 224 // 添加 dept 字段配置
... ... @@ -215,6 +228,7 @@ class DeptDataPermissionRuleTest extends BaseMockitoUnitTest {
215 228 Expression expression = rule.getExpression(tableName, tableAlias);
216 229 // 断言
217 230 assertEquals("u.dept_id IN (10, 20) OR u.id = 1", expression.toString());
  231 + assertSame(deptDataPermission, loginUser.getContext(DeptDataPermissionRule.CONTEXT_KEY, DeptDataPermissionRespDTO.class));
218 232 }
219 233 }
220 234  
... ...
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 {
50 50 */
51 51 private Long tenantId;
52 52  
53   - // ========== UserTypeEnum.ADMIN 独有字段 ==========
54   - // TODO 芋艿:可以通过定义一个 Map<String, String> exts 的方式,去除管理员的字段。不过这样会导致系统比较复杂,所以暂时不去掉先;
55   - /**
56   - * 角色编号数组
57   - */
58   - private Set<Long> roleIds;
59   - /**
60   - * 部门编号
61   - */
62   - private Long deptId;
63   -
64 53 // ========== 上下文 ==========
65 54 /**
66 55 * 上下文字段,不进行持久化
... ...
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
11 11 import org.springframework.util.StringUtils;
12 12  
13 13 import javax.servlet.http.HttpServletRequest;
14   -import java.util.Set;
15 14  
16 15 /**
17 16 * 安全服务工具类
... ... @@ -80,17 +79,6 @@ public class SecurityFrameworkUtils {
80 79 }
81 80  
82 81 /**
83   - * 获得当前用户的角色编号数组
84   - *
85   - * @return 角色编号数组
86   - */
87   - @Nullable
88   - public static Set<Long> getLoginUserRoleIds() {
89   - LoginUser loginUser = getLoginUser();
90   - return loginUser != null ? loginUser.getRoleIds() : null;
91   - }
92   -
93   - /**
94 82 * 设置当前用户
95 83 *
96 84 * @param loginUser 登录用户
... ...
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 {
84 84 @Override
85 85 public String login(AppAuthLoginReqVO reqVO, String userIp, String userAgent) {
86 86 // 使用手机 + 密码,进行登录。
87   - LoginUser loginUser = this.login0(reqVO.getMobile(), reqVO.getPassword());
  87 + LoginUser loginUser = login0(reqVO.getMobile(), reqVO.getPassword());
88 88  
89 89 // 缓存登录用户到 Redis 中,返回 Token 令牌
90 90 return createUserSessionAfterLoginSuccess(loginUser, LoginLogTypeEnum.LOGIN_USERNAME, userIp, userAgent);
... ...
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.*;
26 26 import javax.annotation.Resource;
27 27 import javax.validation.Valid;
28 28 import java.util.List;
  29 +import java.util.Set;
29 30  
30 31 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
31 32 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
32 33 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getUserAgent;
33 34 import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
34   -import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserRoleIds;
  35 +import static java.util.Collections.singleton;
35 36  
36 37 @Api(tags = "管理后台 - 认证")
37 38 @RestController
... ... @@ -69,12 +70,12 @@ public class AuthController {
69 70 return null;
70 71 }
71 72 // 获得角色列表
72   - List<RoleDO> roleList = roleService.getRolesFromCache(getLoginUserRoleIds());
  73 + Set<Long> roleIds = permissionService.getUserRoleIds(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus()));
  74 + List<RoleDO> roleList = roleService.getRolesFromCache(roleIds);
73 75 // 获得菜单列表
74   - List<MenuDO> menuList = permissionService.getRoleMenuListFromCache(
75   - getLoginUserRoleIds(), // 注意,基于登录的角色,因为后续的权限判断也是基于它
  76 + List<MenuDO> menuList = permissionService.getRoleMenuListFromCache(roleIds,
76 77 SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType(), MenuTypeEnum.BUTTON.getType()),
77   - SetUtils.asSet(CommonStatusEnum.ENABLE.getStatus()));
  78 + singleton(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的
78 79 // 拼接结果返回
79 80 return success(AuthConvert.INSTANCE.convert(user, roleList, menuList));
80 81 }
... ... @@ -82,11 +83,12 @@ public class AuthController {
82 83 @GetMapping("/list-menus")
83 84 @ApiOperation("获得登录用户的菜单列表")
84 85 public CommonResult<List<AuthMenuRespVO>> getMenus() {
  86 + // 获得角色列表
  87 + Set<Long> roleIds = permissionService.getUserRoleIds(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus()));
85 88 // 获得用户拥有的菜单列表
86   - List<MenuDO> menuList = permissionService.getRoleMenuListFromCache(
87   - getLoginUserRoleIds(), // 注意,基于登录的角色,因为后续的权限判断也是基于它
  89 + List<MenuDO> menuList = permissionService.getRoleMenuListFromCache(roleIds,
88 90 SetUtils.asSet(MenuTypeEnum.DIR.getType(), MenuTypeEnum.MENU.getType()), // 只要目录和菜单类型
89   - SetUtils.asSet(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的
  91 + singleton(CommonStatusEnum.ENABLE.getStatus())); // 只要开启的
90 92 // 转换成 Tree 结构返回
91 93 return success(AuthConvert.INSTANCE.buildMenuTree(menuList));
92 94 }
... ...
yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/controller/admin/auth/UserSessionController.java
1 1 package cn.iocoder.yudao.module.system.controller.admin.auth;
2 2  
  3 +import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
  4 +import cn.iocoder.yudao.framework.common.pojo.CommonResult;
  5 +import cn.iocoder.yudao.framework.common.pojo.PageResult;
  6 +import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
3 7 import cn.iocoder.yudao.module.system.controller.admin.auth.vo.session.UserSessionPageItemRespVO;
4 8 import cn.iocoder.yudao.module.system.controller.admin.auth.vo.session.UserSessionPageReqVO;
5 9 import cn.iocoder.yudao.module.system.convert.auth.UserSessionConvert;
6 10 import cn.iocoder.yudao.module.system.dal.dataobject.auth.UserSessionDO;
7 11 import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
8   -import cn.iocoder.yudao.module.system.service.auth.UserSessionService;
9 12 import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
10   -import cn.iocoder.yudao.framework.common.pojo.CommonResult;
11   -import cn.iocoder.yudao.framework.common.pojo.PageResult;
12   -import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
  13 +import cn.iocoder.yudao.module.system.service.auth.UserSessionService;
13 14 import cn.iocoder.yudao.module.system.service.dept.DeptService;
14 15 import cn.iocoder.yudao.module.system.service.user.AdminUserService;
15 16 import io.swagger.annotations.Api;
... ... @@ -49,7 +50,8 @@ public class UserSessionController {
49 50  
50 51 // 获得拼接需要的数据
51 52 Map<Long, AdminUserDO> userMap = userService.getUserMap(
52   - convertList(pageResult.getList(), UserSessionDO::getUserId));
  53 + convertList(pageResult.getList(), UserSessionDO::getUserId,
  54 + session -> session.getUserType().equals(UserTypeEnum.ADMIN.getValue())));
53 55 Map<Long, DeptDO> deptMap = deptService.getDeptMap(
54 56 convertList(userMap.values(), AdminUserDO::getDeptId));
55 57 // 拼接结果返回
... ...
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;
17 17 import cn.iocoder.yudao.module.system.enums.sms.SmsSceneEnum;
18 18 import cn.iocoder.yudao.module.system.service.common.CaptchaService;
19 19 import cn.iocoder.yudao.module.system.service.logger.LoginLogService;
20   -import cn.iocoder.yudao.module.system.service.permission.PermissionService;
21 20 import cn.iocoder.yudao.module.system.service.social.SocialUserService;
22 21 import cn.iocoder.yudao.module.system.service.user.AdminUserService;
23 22 import lombok.extern.slf4j.Slf4j;
... ... @@ -36,12 +35,10 @@ import org.springframework.util.Assert;
36 35 import javax.annotation.Resource;
37 36 import javax.validation.Validator;
38 37 import java.util.Objects;
39   -import java.util.Set;
40 38  
41 39 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
42 40 import static cn.iocoder.yudao.framework.common.util.servlet.ServletUtils.getClientIP;
43 41 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
44   -import static java.util.Collections.singleton;
45 42  
46 43 /**
47 44 * Auth Service 实现类
... ... @@ -60,8 +57,6 @@ public class AdminAuthServiceImpl implements AdminAuthService {
60 57 @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection") // UserService 存在重名
61 58 private AdminUserService userService;
62 59 @Resource
63   - private PermissionService permissionService;
64   - @Resource
65 60 private CaptchaService captchaService;
66 61 @Resource
67 62 private LoginLogService loginLogService;
... ... @@ -211,16 +206,6 @@ public class AdminAuthServiceImpl implements AdminAuthService {
211 206 }
212 207 }
213 208  
214   - /**
215   - * 获得 User 拥有的角色编号数组
216   - *
217   - * @param userId 用户编号
218   - * @return 角色编号数组
219   - */
220   - private Set<Long> getUserRoleIds(Long userId) {
221   - return permissionService.getUserRoleIds(userId, singleton(CommonStatusEnum.ENABLE.getStatus()));
222   - }
223   -
224 209 @Override
225 210 public String socialQuickLogin(AuthSocialQuickLoginReqVO reqVO, String userIp, String userAgent) {
226 211 // 使用 code 授权码,进行登录。然后,获得到绑定的用户编号
... ... @@ -318,17 +303,13 @@ public class AdminAuthServiceImpl implements AdminAuthService {
318 303 }
319 304  
320 305 // 刷新 LoginUser 缓存
321   - LoginUser newLoginUser= this.buildLoginUser(user);
  306 + LoginUser newLoginUser= buildLoginUser(user);
322 307 userSessionService.refreshUserSession(token, newLoginUser);
323 308 return newLoginUser;
324 309 }
325 310  
326 311 private LoginUser buildLoginUser(AdminUserDO user) {
327   - LoginUser loginUser = AuthConvert.INSTANCE.convert(user);
328   - // 补全字段
329   - loginUser.setDeptId(user.getDeptId());
330   - loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId()));
331   - return loginUser;
  312 + return AuthConvert.INSTANCE.convert(user);
332 313 }
333 314  
334 315 }
... ...
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;
3 3 import cn.hutool.core.collection.CollUtil;
4 4 import cn.hutool.core.collection.CollectionUtil;
5 5 import cn.hutool.core.util.ArrayUtil;
  6 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
6 7 import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
7 8 import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
8 9 import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
  10 +import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
9 11 import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO;
10   -import cn.iocoder.yudao.framework.security.core.LoginUser;
11   -import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
12 12 import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
13 13 import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
14 14 import cn.iocoder.yudao.module.system.dal.dataobject.permission.MenuDO;
... ... @@ -22,6 +22,8 @@ import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleMapper;
22 22 import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum;
23 23 import cn.iocoder.yudao.module.system.mq.producer.permission.PermissionProducer;
24 24 import cn.iocoder.yudao.module.system.service.dept.DeptService;
  25 +import cn.iocoder.yudao.module.system.service.user.AdminUserService;
  26 +import com.google.common.base.Suppliers;
25 27 import com.google.common.collect.ImmutableMultimap;
26 28 import com.google.common.collect.Multimap;
27 29 import com.google.common.collect.Sets;
... ... @@ -36,6 +38,10 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
36 38 import javax.annotation.PostConstruct;
37 39 import javax.annotation.Resource;
38 40 import java.util.*;
  41 +import java.util.function.Supplier;
  42 +
  43 +import static cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
  44 +import static java.util.Collections.singleton;
39 45  
40 46 /**
41 47 * 权限 Service 实现类
... ... @@ -47,11 +53,6 @@ import java.util.*;
47 53 public class PermissionServiceImpl implements PermissionService {
48 54  
49 55 /**
50   - * LoginUser 的 Context 缓存 Key
51   - */
52   - public static final String CONTEXT_KEY = PermissionServiceImpl.class.getSimpleName();
53   -
54   - /**
55 56 * 定时执行 {@link #schedulePeriodicRefresh()} 的周期
56 57 * 因为已经通过 Redis Pub/Sub 机制,所以频率不需要高
57 58 */
... ... @@ -93,6 +94,8 @@ public class PermissionServiceImpl implements PermissionService {
93 94 private MenuService menuService;
94 95 @Resource
95 96 private DeptService deptService;
  97 + @Resource
  98 + private AdminUserService userService;
96 99  
97 100 @Resource
98 101 private PermissionProducer permissionProducer;
... ... @@ -319,7 +322,7 @@ public class PermissionServiceImpl implements PermissionService {
319 322 }
320 323  
321 324 // 获得当前登录的角色。如果为空,说明没有权限
322   - Set<Long> roleIds = SecurityFrameworkUtils.getLoginUserRoleIds();
  325 + Set<Long> roleIds = getUserRoleIds(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus()));
323 326 if (CollUtil.isEmpty(roleIds)) {
324 327 return false;
325 328 }
... ... @@ -354,7 +357,7 @@ public class PermissionServiceImpl implements PermissionService {
354 357 }
355 358  
356 359 // 获得当前登录的角色。如果为空,说明没有权限
357   - Set<Long> roleIds = SecurityFrameworkUtils.getLoginUserRoleIds();
  360 + Set<Long> roleIds = getUserRoleIds(getLoginUserId(), singleton(CommonStatusEnum.ENABLE.getStatus()));
358 361 if (CollUtil.isEmpty(roleIds)) {
359 362 return false;
360 363 }
... ... @@ -368,16 +371,18 @@ public class PermissionServiceImpl implements PermissionService {
368 371 }
369 372  
370 373 @Override
371   - public DeptDataPermissionRespDTO getDeptDataPermission(LoginUser loginUser) {
372   - // 判断是否 context 已经缓存
373   - DeptDataPermissionRespDTO result = loginUser.getContext(CONTEXT_KEY, DeptDataPermissionRespDTO.class);
374   - if (result != null) {
  374 + @DataPermission(enable = false) // 关闭数据权限,不然就会出现递归获取数据权限的问题
  375 + public DeptDataPermissionRespDTO getDeptDataPermission(Long userId) {
  376 + DeptDataPermissionRespDTO result = new DeptDataPermissionRespDTO();
  377 + // 获得用户的角色
  378 + Set<Long> roleIds = getUserRoleIds(userId, singleton(CommonStatusEnum.ENABLE.getStatus()));
  379 + if (CollUtil.isEmpty(roleIds)) {
375 380 return result;
376 381 }
377   -
378   - // 创建 DeptDataPermissionRespDTO 对象
379   - result = new DeptDataPermissionRespDTO();
380   - List<RoleDO> roles = roleService.getRolesFromCache(loginUser.getRoleIds());
  382 + List<RoleDO> roles = roleService.getRolesFromCache(roleIds);
  383 + // 获得用户的部门编号的缓存,通过 Guava 的 Suppliers 惰性求值,即有且仅有第一次发起 DB 的查询
  384 + Supplier<Long> userDeptIdCache = Suppliers.memoize(() -> userService.getUser(userId).getDeptId());
  385 + // 遍历每个角色,计算
381 386 for (RoleDO role : roles) {
382 387 // 为空时,跳过
383 388 if (role.getDataScope() == null) {
... ... @@ -393,20 +398,20 @@ public class PermissionServiceImpl implements PermissionService {
393 398 CollUtil.addAll(result.getDeptIds(), role.getDataScopeDeptIds());
394 399 // 自定义可见部门时,保证可以看到自己所在的部门。否则,一些场景下可能会有问题。
395 400 // 例如说,登录时,基于 t_user 的 username 查询会可能被 dept_id 过滤掉
396   - CollUtil.addAll(result.getDeptIds(), loginUser.getDeptId());
  401 + CollUtil.addAll(result.getDeptIds(), userDeptIdCache.get());
397 402 continue;
398 403 }
399 404 // 情况三,DEPT_ONLY
400 405 if (Objects.equals(role.getDataScope(), DataScopeEnum.DEPT_ONLY.getScope())) {
401   - CollectionUtils.addIfNotNull(result.getDeptIds(), loginUser.getDeptId());
  406 + CollectionUtils.addIfNotNull(result.getDeptIds(), userDeptIdCache.get());
402 407 continue;
403 408 }
404 409 // 情况四,DEPT_DEPT_AND_CHILD
405 410 if (Objects.equals(role.getDataScope(), DataScopeEnum.DEPT_AND_CHILD.getScope())) {
406   - List<DeptDO> depts = deptService.getDeptsByParentIdFromCache(loginUser.getDeptId(), true);
  411 + List<DeptDO> depts = deptService.getDeptsByParentIdFromCache(userDeptIdCache.get(), true);
407 412 CollUtil.addAll(result.getDeptIds(), CollectionUtils.convertList(depts, DeptDO::getId));
408   - //添加本身部门id
409   - CollUtil.addAll(result.getDeptIds(), loginUser.getDeptId());
  413 + // 添加本身部门编号
  414 + CollUtil.addAll(result.getDeptIds(), userDeptIdCache.get());
410 415 continue;
411 416 }
412 417 // 情况五,SELF
... ... @@ -415,11 +420,8 @@ public class PermissionServiceImpl implements PermissionService {
415 420 continue;
416 421 }
417 422 // 未知情况,error log 即可
418   - log.error("[getDeptDataPermission][LoginUser({}) role({}) 无法处理]", loginUser.getId(), JsonUtils.toJsonString(result));
  423 + log.error("[getDeptDataPermission][LoginUser({}) role({}) 无法处理]", userId, JsonUtils.toJsonString(result));
419 424 }
420   -
421   - // 添加到缓存,并返回
422   - loginUser.setContext(CONTEXT_KEY, result);
423 425 return result;
424 426 }
425 427  
... ...
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 {
81 81 @Getter
82 82 private volatile Date maxUpdateTime;
83 83  
  84 + @SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")
84 85 @Autowired(required = false) // 由于 yudao.tenant.enable 配置项,可以关闭多租户的功能,所以这里只能不强制注入
85 86 private TenantProperties tenantProperties;
86 87  
... ...
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;
25 25 import com.google.common.annotations.VisibleForTesting;
26 26 import lombok.extern.slf4j.Slf4j;
27 27 import org.springframework.beans.factory.annotation.Value;
  28 +import org.springframework.context.annotation.Lazy;
28 29 import org.springframework.security.crypto.password.PasswordEncoder;
29 30 import org.springframework.stereotype.Service;
30 31 import org.springframework.transaction.annotation.Transactional;
... ... @@ -61,6 +62,7 @@ public class AdminUserServiceImpl implements AdminUserService {
61 62 @Resource
62 63 private PasswordEncoder passwordEncoder;
63 64 @Resource
  65 + @Lazy // 延迟,避免循环依赖报错
64 66 private TenantService tenantService;
65 67  
66 68 @Resource
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/auth/AuthServiceImplTest.java
1 1 package cn.iocoder.yudao.module.system.service.auth;
2 2  
3   -import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
4 3 import cn.iocoder.yudao.framework.security.core.LoginUser;
5 4 import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
6 5 import cn.iocoder.yudao.framework.test.core.util.AssertUtils;
... ... @@ -12,7 +11,6 @@ import cn.iocoder.yudao.module.system.enums.logger.LoginResultEnum;
12 11 import cn.iocoder.yudao.module.system.service.common.CaptchaService;
13 12 import cn.iocoder.yudao.module.system.service.dept.PostService;
14 13 import cn.iocoder.yudao.module.system.service.logger.LoginLogService;
15   -import cn.iocoder.yudao.module.system.service.permission.PermissionService;
16 14 import cn.iocoder.yudao.module.system.service.social.SocialUserService;
17 15 import cn.iocoder.yudao.module.system.service.user.AdminUserService;
18 16 import org.junit.jupiter.api.BeforeEach;
... ... @@ -34,7 +32,6 @@ import java.util.Set;
34 32 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertServiceException;
35 33 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.*;
36 34 import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
37   -import static java.util.Collections.singleton;
38 35 import static org.junit.jupiter.api.Assertions.assertEquals;
39 36 import static org.junit.jupiter.api.Assertions.assertThrows;
40 37 import static org.mockito.ArgumentMatchers.eq;
... ... @@ -49,8 +46,6 @@ public class AuthServiceImplTest extends BaseDbUnitTest {
49 46 @MockBean
50 47 private AdminUserService userService;
51 48 @MockBean
52   - private PermissionService permissionService;
53   - @MockBean
54 49 private AuthenticationManager authenticationManager;
55 50 @MockBean
56 51 private Authentication authentication;
... ... @@ -108,16 +103,11 @@ public class AuthServiceImplTest extends BaseDbUnitTest {
108 103 // mock 方法 01
109 104 AdminUserDO user = randomPojo(AdminUserDO.class, o -> o.setId(userId));
110 105 when(userService.getUser(eq(userId))).thenReturn(user);
111   - // mock 方法 02
112   - Set<Long> roleIds = randomSet(Long.class);
113   - when(permissionService.getUserRoleIds(eq(userId), eq(singleton(CommonStatusEnum.ENABLE.getStatus()))))
114   - .thenReturn(roleIds);
115 106  
116 107 // 调用
117 108 LoginUser loginUser = authService.mockLogin(userId);
118 109 // 断言
119 110 AssertUtils.assertPojoEquals(user, loginUser, "updateTime");
120   - assertEquals(roleIds, loginUser.getRoleIds());
121 111 }
122 112  
123 113 @Test
... ... @@ -247,15 +237,10 @@ public class AuthServiceImplTest extends BaseDbUnitTest {
247 237 // mock authentication
248 238 Long userId = randomLongId();
249 239 Set<Long> userRoleIds = randomSet(Long.class);
250   - LoginUser loginUser = randomPojo(LoginUser.class, o -> {
251   - o.setId(userId);
252   - o.setRoleIds(userRoleIds);
253   - });
  240 + LoginUser loginUser = randomPojo(LoginUser.class, o -> o.setId(userId));
254 241 when(authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(reqVO.getUsername(), reqVO.getPassword())))
255 242 .thenReturn(authentication);
256 243 when(authentication.getPrincipal()).thenReturn(loginUser);
257   - // mock 获得 User 拥有的角色编号数组
258   - when(permissionService.getUserRoleIds(userId, singleton(CommonStatusEnum.ENABLE.getStatus()))).thenReturn(userRoleIds);
259 244 // mock 缓存登录用户到 Redis
260 245 String token = randomString();
261 246 when(userSessionService.createUserSession(loginUser, userIp, userAgent)).thenReturn(token);
... ...
yudao-module-system/yudao-module-system-biz/src/test/java/cn/iocoder/yudao/module/system/service/permission/PermissionServiceTest.java
1 1 package cn.iocoder.yudao.module.system.service.permission;
2 2  
3 3 import cn.hutool.core.collection.CollUtil;
  4 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
  5 +import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO;
  6 +import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
4 7 import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
5 8 import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
6 9 import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleMenuDO;
7 10 import cn.iocoder.yudao.module.system.dal.dataobject.permission.UserRoleDO;
  11 +import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
8 12 import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMenuBatchInsertMapper;
9 13 import cn.iocoder.yudao.module.system.dal.mysql.permission.RoleMenuMapper;
10 14 import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleBatchInsertMapper;
11 15 import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleMapper;
  16 +import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum;
12 17 import cn.iocoder.yudao.module.system.mq.producer.permission.PermissionProducer;
13 18 import cn.iocoder.yudao.module.system.service.dept.DeptService;
14   -import cn.iocoder.yudao.framework.datapermission.core.dept.service.dto.DeptDataPermissionRespDTO;
15   -import cn.iocoder.yudao.framework.security.core.LoginUser;
16   -import cn.iocoder.yudao.module.system.enums.permission.DataScopeEnum;
17   -import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
  19 +import cn.iocoder.yudao.module.system.service.user.AdminUserService;
18 20 import org.junit.jupiter.api.Test;
19 21 import org.springframework.boot.test.mock.mockito.MockBean;
20 22 import org.springframework.context.annotation.Import;
... ... @@ -25,10 +27,10 @@ import java.util.List;
25 27 import static cn.iocoder.yudao.framework.test.core.util.AssertUtils.assertPojoEquals;
26 28 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomLongId;
27 29 import static cn.iocoder.yudao.framework.test.core.util.RandomUtils.randomPojo;
  30 +import static java.util.Collections.singleton;
28 31 import static java.util.Collections.singletonList;
29 32 import static org.junit.jupiter.api.Assertions.*;
30 33 import static org.mockito.ArgumentMatchers.eq;
31   -import static org.mockito.ArgumentMatchers.same;
32 34 import static org.mockito.Mockito.verify;
33 35 import static org.mockito.Mockito.when;
34 36  
... ... @@ -55,6 +57,9 @@ public class PermissionServiceTest extends BaseDbUnitTest {
55 57 @MockBean
56 58 private DeptService deptService;
57 59 @MockBean
  60 + private AdminUserService userService;
  61 +
  62 + @MockBean
58 63 private PermissionProducer permissionProducer;
59 64  
60 65 @Test
... ... @@ -124,112 +129,119 @@ public class PermissionServiceTest extends BaseDbUnitTest {
124 129 assertPojoEquals(dbUserRoles.get(0), userRoleDO02);
125 130 }
126 131  
127   - @Test // 测试从 context 获取的场景
128   - public void testGetDeptDataPermission_fromContext() {
129   - // 准备参数
130   - LoginUser loginUser = randomPojo(LoginUser.class);
131   - // mock 方法
132   - DeptDataPermissionRespDTO respDTO = new DeptDataPermissionRespDTO();
133   - loginUser.setContext(PermissionServiceImpl.CONTEXT_KEY, respDTO);
134   -
135   - // 调用
136   - DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(loginUser);
137   - // 断言
138   - assertSame(respDTO, result);
139   - }
140   -
141 132 @Test
142 133 public void testGetDeptDataPermission_All() {
143 134 // 准备参数
144   - LoginUser loginUser = randomPojo(LoginUser.class);
145   - // mock 方法
146   - RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.ALL.getScope()));
147   - when(roleService.getRolesFromCache(same(loginUser.getRoleIds()))).thenReturn(singletonList(roleDO));
  135 + Long userId = 1L;
  136 + // mock 用户的角色编号
  137 + userRoleMapper.insert(new UserRoleDO().setUserId(userId).setRoleId(2L));
  138 + // mock 获得用户的角色
  139 + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.ALL.getScope())
  140 + .setStatus(CommonStatusEnum.ENABLE.getStatus()));
  141 + when(roleService.getRolesFromCache(eq(singleton(2L)))).thenReturn(singletonList(roleDO));
  142 + when(roleService.getRoleFromCache(eq(2L))).thenReturn(roleDO);
148 143  
149 144 // 调用
150   - DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(loginUser);
  145 + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId);
151 146 // 断言
152 147 assertTrue(result.getAll());
153 148 assertFalse(result.getSelf());
154 149 assertTrue(CollUtil.isEmpty(result.getDeptIds()));
155   - assertSame(result, loginUser.getContext(PermissionServiceImpl.CONTEXT_KEY, DeptDataPermissionRespDTO.class));
156 150 }
157 151  
158 152 @Test
159 153 public void testGetDeptDataPermission_DeptCustom() {
160 154 // 准备参数
161   - LoginUser loginUser = randomPojo(LoginUser.class);
162   - // mock 方法
163   - RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_CUSTOM.getScope()));
164   - when(roleService.getRolesFromCache(same(loginUser.getRoleIds()))).thenReturn(singletonList(roleDO));
  155 + Long userId = 1L;
  156 + // mock 用户的角色编号
  157 + userRoleMapper.insert(new UserRoleDO().setUserId(userId).setRoleId(2L));
  158 + // mock 获得用户的角色
  159 + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_CUSTOM.getScope())
  160 + .setStatus(CommonStatusEnum.ENABLE.getStatus()));
  161 + when(roleService.getRolesFromCache(eq(singleton(2L)))).thenReturn(singletonList(roleDO));
  162 + when(roleService.getRoleFromCache(eq(2L))).thenReturn(roleDO);
  163 + // mock 部门的返回
  164 + when(userService.getUser(eq(1L))).thenReturn(new AdminUserDO().setDeptId(3L), null, null); // 最后返回 null 的目的,看看会不会重复调用
165 165  
166 166 // 调用
167   - DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(loginUser);
  167 + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(1L);
168 168 // 断言
169 169 assertFalse(result.getAll());
170 170 assertFalse(result.getSelf());
171 171 assertEquals(roleDO.getDataScopeDeptIds().size() + 1, result.getDeptIds().size());
172 172 assertTrue(CollUtil.containsAll(result.getDeptIds(), roleDO.getDataScopeDeptIds()));
173   - assertTrue(CollUtil.contains(result.getDeptIds(), loginUser.getDeptId()));
174   - assertSame(result, loginUser.getContext(PermissionServiceImpl.CONTEXT_KEY, DeptDataPermissionRespDTO.class));
  173 + assertTrue(CollUtil.contains(result.getDeptIds(), 3L));
175 174 }
176 175  
177 176 @Test
178 177 public void testGetDeptDataPermission_DeptOnly() {
179 178 // 准备参数
180   - LoginUser loginUser = randomPojo(LoginUser.class);
181   - // mock 方法
182   - RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_ONLY.getScope()));
183   - when(roleService.getRolesFromCache(same(loginUser.getRoleIds()))).thenReturn(singletonList(roleDO));
  179 + Long userId = 1L;
  180 + // mock 用户的角色编号
  181 + userRoleMapper.insert(new UserRoleDO().setUserId(userId).setRoleId(2L));
  182 + // mock 获得用户的角色
  183 + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_ONLY.getScope())
  184 + .setStatus(CommonStatusEnum.ENABLE.getStatus()));
  185 + when(roleService.getRolesFromCache(eq(singleton(2L)))).thenReturn(singletonList(roleDO));
  186 + when(roleService.getRoleFromCache(eq(2L))).thenReturn(roleDO);
  187 + // mock 部门的返回
  188 + when(userService.getUser(eq(1L))).thenReturn(new AdminUserDO().setDeptId(3L), null, null); // 最后返回 null 的目的,看看会不会重复调用
184 189  
185 190 // 调用
186   - DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(loginUser);
  191 + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(1L);
187 192 // 断言
188 193 assertFalse(result.getAll());
189 194 assertFalse(result.getSelf());
190 195 assertEquals(1, result.getDeptIds().size());
191   - assertTrue(CollUtil.contains(result.getDeptIds(), loginUser.getDeptId()));
192   - assertSame(result, loginUser.getContext(PermissionServiceImpl.CONTEXT_KEY, DeptDataPermissionRespDTO.class));
  196 + assertTrue(CollUtil.contains(result.getDeptIds(), 3L));
193 197 }
194 198  
195 199 @Test
196 200 public void testGetDeptDataPermission_DeptAndChild() {
197 201 // 准备参数
198   - LoginUser loginUser = randomPojo(LoginUser.class);
199   - // mock 方法(角色)
200   - RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_AND_CHILD.getScope()));
201   - when(roleService.getRolesFromCache(same(loginUser.getRoleIds()))).thenReturn(singletonList(roleDO));
  202 + Long userId = 1L;
  203 + // mock 用户的角色编号
  204 + userRoleMapper.insert(new UserRoleDO().setUserId(userId).setRoleId(2L));
  205 + // mock 获得用户的角色
  206 + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.DEPT_AND_CHILD.getScope())
  207 + .setStatus(CommonStatusEnum.ENABLE.getStatus()));
  208 + when(roleService.getRolesFromCache(eq(singleton(2L)))).thenReturn(singletonList(roleDO));
  209 + when(roleService.getRoleFromCache(eq(2L))).thenReturn(roleDO);
  210 + // mock 部门的返回
  211 + when(userService.getUser(eq(1L))).thenReturn(new AdminUserDO().setDeptId(3L), null, null); // 最后返回 null 的目的,看看会不会重复调用
202 212 // mock 方法(部门)
203 213 DeptDO deptDO = randomPojo(DeptDO.class);
204   - when(deptService.getDeptsByParentIdFromCache(eq(loginUser.getDeptId()), eq(true)))
  214 + when(deptService.getDeptsByParentIdFromCache(eq(3L), eq(true)))
205 215 .thenReturn(singletonList(deptDO));
206 216  
207 217 // 调用
208   - DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(loginUser);
  218 + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId);
209 219 // 断言
210 220 assertFalse(result.getAll());
211 221 assertFalse(result.getSelf());
212 222 assertEquals(2, result.getDeptIds().size());
213 223 assertTrue(CollUtil.contains(result.getDeptIds(), deptDO.getId()));
214   - assertTrue(CollUtil.contains(result.getDeptIds(), loginUser.getDeptId()));
215   - assertSame(result, loginUser.getContext(PermissionServiceImpl.CONTEXT_KEY, DeptDataPermissionRespDTO.class));
  224 + assertTrue(CollUtil.contains(result.getDeptIds(), 3L));
216 225 }
217 226  
218 227 @Test
219 228 public void testGetDeptDataPermission_Self() {
220 229 // 准备参数
221   - LoginUser loginUser = randomPojo(LoginUser.class);
222   - // mock 方法
223   - RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.SELF.getScope()));
224   - when(roleService.getRolesFromCache(same(loginUser.getRoleIds()))).thenReturn(singletonList(roleDO));
  230 + Long userId = 1L;
  231 + // mock 用户的角色编号
  232 + userRoleMapper.insert(new UserRoleDO().setUserId(userId).setRoleId(2L));
  233 + // mock 获得用户的角色
  234 + RoleDO roleDO = randomPojo(RoleDO.class, o -> o.setDataScope(DataScopeEnum.SELF.getScope())
  235 + .setStatus(CommonStatusEnum.ENABLE.getStatus()));
  236 + when(roleService.getRolesFromCache(eq(singleton(2L)))).thenReturn(singletonList(roleDO));
  237 + when(roleService.getRoleFromCache(eq(2L))).thenReturn(roleDO);
225 238  
226 239 // 调用
227   - DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(loginUser);
  240 + DeptDataPermissionRespDTO result = permissionService.getDeptDataPermission(userId);
228 241 // 断言
229 242 assertFalse(result.getAll());
230 243 assertTrue(result.getSelf());
231 244 assertTrue(CollUtil.isEmpty(result.getDeptIds()));
232   - assertSame(result, loginUser.getContext(PermissionServiceImpl.CONTEXT_KEY, DeptDataPermissionRespDTO.class));
233 245 }
234 246  
235 247 }
... ...