Commit 986cb72421c35b514709e2cafebc22a412a22646
1 parent
b0855cc6
基于部门的数据权限
Showing
15 changed files
with
409 additions
and
36 deletions
yudao-admin-server/pom.xml
| @@ -123,6 +123,11 @@ | @@ -123,6 +123,11 @@ | ||
| 123 | </dependency> | 123 | </dependency> |
| 124 | 124 | ||
| 125 | <dependency> | 125 | <dependency> |
| 126 | + <groupId>cn.iocoder.boot</groupId> | ||
| 127 | + <artifactId>yudao-spring-boot-starter-data-permission</artifactId> | ||
| 128 | + </dependency> | ||
| 129 | + | ||
| 130 | + <dependency> | ||
| 126 | <groupId>org.apache.velocity</groupId> | 131 | <groupId>org.apache.velocity</groupId> |
| 127 | <artifactId>velocity-engine-core</artifactId> | 132 | <artifactId>velocity-engine-core</artifactId> |
| 128 | </dependency> | 133 | </dependency> |
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/datapermission/core/rule/DeptDataPermissionRule.java
0 → 100644
| 1 | +package cn.iocoder.yudao.adminserver.framework.datapermission.core.rule; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 4 | +import cn.hutool.core.util.StrUtil; | ||
| 5 | +import cn.iocoder.yudao.adminserver.framework.datapermission.core.service.DeptDataPermissionService; | ||
| 6 | +import cn.iocoder.yudao.adminserver.framework.datapermission.core.service.dto.DeptDataPermissionRespDTO; | ||
| 7 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||
| 8 | +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | ||
| 9 | +import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule; | ||
| 10 | +import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; | ||
| 11 | +import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; | ||
| 12 | +import cn.iocoder.yudao.framework.security.core.LoginUser; | ||
| 13 | +import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils; | ||
| 14 | +import com.baomidou.mybatisplus.core.metadata.TableInfoHelper; | ||
| 15 | +import lombok.AllArgsConstructor; | ||
| 16 | +import lombok.extern.slf4j.Slf4j; | ||
| 17 | +import net.sf.jsqlparser.expression.Alias; | ||
| 18 | +import net.sf.jsqlparser.expression.Expression; | ||
| 19 | +import net.sf.jsqlparser.expression.LongValue; | ||
| 20 | +import net.sf.jsqlparser.expression.operators.conditional.OrExpression; | ||
| 21 | +import net.sf.jsqlparser.expression.operators.relational.EqualsTo; | ||
| 22 | +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; | ||
| 23 | +import net.sf.jsqlparser.expression.operators.relational.InExpression; | ||
| 24 | + | ||
| 25 | +import java.util.HashMap; | ||
| 26 | +import java.util.HashSet; | ||
| 27 | +import java.util.Map; | ||
| 28 | +import java.util.Set; | ||
| 29 | + | ||
| 30 | +/** | ||
| 31 | + * 基于部门的 {@link DataPermissionRule} 数据权限规则实现 | ||
| 32 | + * | ||
| 33 | + * 注意,使用 DeptDataPermissionRule 时,需要保证表中有 dept_id 部门编号的字段,可自定义。 | ||
| 34 | + * | ||
| 35 | + * 实际业务场景下,会存在一个经典的问题?当用户修改部门时,冗余的 dept_id 是否需要修改? | ||
| 36 | + * 1. 一般情况下,dept_id 不进行修改,则会导致用户看到之前的数据。【yudao-admin-server 采用该方案】 | ||
| 37 | + * 2. 部分情况下,希望该用户还是能看到之前的数据,则有两种方式解决:【需要你改造该 DeptDataPermissionRule 的实现代码】 | ||
| 38 | + * 1)编写洗数据的脚本,将 dept_id 修改成新部门的编号;【建议】 | ||
| 39 | + * 最终过滤条件是 WHERE dept_id = ? | ||
| 40 | + * 2)洗数据的话,可能涉及的数据量较大,也可以采用 user_id 进行过滤的方式,此时需要获取到 dept_id 对应的所有 user_id 用户编号; | ||
| 41 | + * 最终过滤条件是 WHERE user_id IN (?, ?, ? ...) | ||
| 42 | + * 3)想要保证原 dept_id 和 user_id 都可以看的到,此时使用 dept_id 和 user_id 一起过滤; | ||
| 43 | + * 最终过滤条件是 WHERE dept_id = ? OR user_id IN (?, ?, ? ...) | ||
| 44 | + * | ||
| 45 | + * @author 芋道源码 | ||
| 46 | + */ | ||
| 47 | +@AllArgsConstructor | ||
| 48 | +@Slf4j | ||
| 49 | +public class DeptDataPermissionRule implements DataPermissionRule { | ||
| 50 | + | ||
| 51 | + private static final String DEPT_COLUMN_NAME = "dept_id"; | ||
| 52 | + private static final String USER_COLUMN_NAME = "user_id"; | ||
| 53 | + | ||
| 54 | + private final DeptDataPermissionService deptDataPermissionService; | ||
| 55 | + | ||
| 56 | + /** | ||
| 57 | + * 基于部门的表字段配置 | ||
| 58 | + * 一般情况下,每个表的部门编号字段是 dept_id,通过该配置自定义。 | ||
| 59 | + * | ||
| 60 | + * key:表名 | ||
| 61 | + * value:字段名 | ||
| 62 | + */ | ||
| 63 | + private final Map<String, String> DEPT_TABLE_CONFIG = new HashMap<>(); | ||
| 64 | + /** | ||
| 65 | + * 基于用户的表字段配置 | ||
| 66 | + * 一般情况下,每个表的部门编号字段是 dept_id,通过该配置自定义。 | ||
| 67 | + * | ||
| 68 | + * key:表名 | ||
| 69 | + * value:字段名 | ||
| 70 | + */ | ||
| 71 | + private final Map<String, String> USER_TABLE_CONFIG = new HashMap<>(); | ||
| 72 | + /** | ||
| 73 | + * 所有表名,是 {@link #DEPT_TABLE_CONFIG} 和 {@link #USER_TABLE_CONFIG} 的合集 | ||
| 74 | + */ | ||
| 75 | + private final Set<String> TABLE_NAMES = new HashSet<>(); | ||
| 76 | + | ||
| 77 | + @Override | ||
| 78 | + public Set<String> getTableNames() { | ||
| 79 | + return TABLE_NAMES; | ||
| 80 | + } | ||
| 81 | + | ||
| 82 | + @Override | ||
| 83 | + public Expression getExpression(String tableName, Alias tableAlias) { | ||
| 84 | + // 只有有登陆用户的情况下,才进行数据权限的处理 | ||
| 85 | + LoginUser loginUser = SecurityFrameworkUtils.getLoginUser(); | ||
| 86 | + if (loginUser == null) { | ||
| 87 | + return null; | ||
| 88 | + } | ||
| 89 | + | ||
| 90 | + // 获得数据权限 | ||
| 91 | + DeptDataPermissionRespDTO deptDataPermission = deptDataPermissionService.getDeptDataPermission(loginUser); | ||
| 92 | + if (deptDataPermission == null) { | ||
| 93 | + log.error("[getExpression][LoginUser({}) 获取数据权限为 null]", JsonUtils.toJsonString(loginUser)); | ||
| 94 | + return null; | ||
| 95 | + } | ||
| 96 | + | ||
| 97 | + // 情况一,如果是 ALL 可查看全部,则无需拼接条件 | ||
| 98 | + if (deptDataPermission.getAll()) { | ||
| 99 | + return null; | ||
| 100 | + } | ||
| 101 | + | ||
| 102 | + // 情况二,即不能查看部门,又不能查看自己,则说明 100% 无权限 | ||
| 103 | + if (CollUtil.isEmpty(deptDataPermission.getDeptIds()) | ||
| 104 | + && Boolean.FALSE.equals(deptDataPermission.getSelf())) { | ||
| 105 | + return new EqualsTo(null, null); // WHERE null = null,可以保证返回的数据为空 | ||
| 106 | + } | ||
| 107 | + | ||
| 108 | + // 情况三,拼接 Dept 和 User 的条件,最后组合 | ||
| 109 | + Expression deptExpression = this.buildDeptExpression(tableName,tableAlias, deptDataPermission.getDeptIds()); | ||
| 110 | + Expression userExpression = this.buildUserExpression(tableName, tableAlias, deptDataPermission.getSelf(), loginUser.getId()); | ||
| 111 | + if (deptExpression == null && userExpression == null) { | ||
| 112 | + log.error("[getExpression][LoginUser({}) Table({}/{}) DeptDataPermission({}) 构建的条件为空]", | ||
| 113 | + JsonUtils.toJsonString(loginUser), tableName, tableAlias, JsonUtils.toJsonString(deptDataPermission)); | ||
| 114 | + throw new NullPointerException(String.format("LoginUser(%d) tableName(%s) tableAlias(%s) 构建的条件为空", | ||
| 115 | + loginUser.getId(), tableName, tableAlias.getName())); | ||
| 116 | + } | ||
| 117 | + if (deptExpression == null) { | ||
| 118 | + return userExpression; | ||
| 119 | + } | ||
| 120 | + if (userExpression == null) { | ||
| 121 | + return deptExpression; | ||
| 122 | + } | ||
| 123 | + // 目前,如果有指定部门 + 可查看自己,采用 OR 条件。即,WHERE dept_id IN ? OR user_id = ? | ||
| 124 | + return new OrExpression(deptExpression, userExpression); | ||
| 125 | + } | ||
| 126 | + | ||
| 127 | + private Expression buildDeptExpression(String tableName, Alias tableAlias, Set<Long> deptIds) { | ||
| 128 | + // 如果不存在配置,则无需作为条件 | ||
| 129 | + String columnName = DEPT_TABLE_CONFIG.get(tableName); | ||
| 130 | + if (StrUtil.isEmpty(columnName)) { | ||
| 131 | + return null; | ||
| 132 | + } | ||
| 133 | + // 拼接条件 | ||
| 134 | + return new InExpression(MyBatisUtils.buildColumn(tableName, tableAlias, columnName), | ||
| 135 | + new ExpressionList(CollectionUtils.convertList(deptIds, LongValue::new))); | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + private Expression buildUserExpression(String tableName, Alias tableAlias, Boolean self, Long userId) { | ||
| 139 | + // 如果不查看自己,则无需作为条件 | ||
| 140 | + if (Boolean.FALSE.equals(self)) { | ||
| 141 | + return null; | ||
| 142 | + } | ||
| 143 | + String columnName = USER_TABLE_CONFIG.get(tableName); | ||
| 144 | + if (StrUtil.isEmpty(columnName)) { | ||
| 145 | + return null; | ||
| 146 | + } | ||
| 147 | + // 拼接条件 | ||
| 148 | + return new EqualsTo(MyBatisUtils.buildColumn(tableName, tableAlias, columnName), new LongValue(userId)); | ||
| 149 | + } | ||
| 150 | + | ||
| 151 | + // ==================== 添加配置 ==================== | ||
| 152 | + | ||
| 153 | + public void addDeptTableConfig(Class<? extends BaseDO> entityClass) { | ||
| 154 | + addDeptTableConfig(entityClass, DEPT_COLUMN_NAME); | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + public void addDeptTableConfig(Class<? extends BaseDO> entityClass, String columnName) { | ||
| 158 | + String tableName = TableInfoHelper.getTableInfo(entityClass).getTableName(); | ||
| 159 | + DEPT_TABLE_CONFIG.put(tableName, columnName); | ||
| 160 | + TABLE_NAMES.add(tableName); | ||
| 161 | + } | ||
| 162 | + | ||
| 163 | + public void addUserTableConfig(Class<? extends BaseDO> entityClass) { | ||
| 164 | + addUserTableConfig(entityClass, DEPT_COLUMN_NAME); | ||
| 165 | + } | ||
| 166 | + | ||
| 167 | + public void addUserTableConfig(Class<? extends BaseDO> entityClass, String columnName) { | ||
| 168 | + String tableName = TableInfoHelper.getTableInfo(entityClass).getTableName(); | ||
| 169 | + USER_TABLE_CONFIG.put(tableName, columnName); | ||
| 170 | + TABLE_NAMES.add(tableName); | ||
| 171 | + } | ||
| 172 | + | ||
| 173 | +} |
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/datapermission/core/service/DeptDataPermissionService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.adminserver.framework.datapermission.core.service; | ||
| 2 | + | ||
| 3 | +import cn.iocoder.yudao.adminserver.framework.datapermission.core.service.dto.DeptDataPermissionRespDTO; | ||
| 4 | +import cn.iocoder.yudao.framework.security.core.LoginUser; | ||
| 5 | + | ||
| 6 | +/** | ||
| 7 | + * 基于部门的数据权限 Service 接口 | ||
| 8 | + * | ||
| 9 | + * @author 芋道源码 | ||
| 10 | + */ | ||
| 11 | +public interface DeptDataPermissionService { | ||
| 12 | + | ||
| 13 | + /** | ||
| 14 | + * 获得登陆用户的部门数据权限 | ||
| 15 | + * | ||
| 16 | + * @param loginUser 登陆用户 | ||
| 17 | + * @return 部门数据权限 | ||
| 18 | + */ | ||
| 19 | + DeptDataPermissionRespDTO getDeptDataPermission(LoginUser loginUser); | ||
| 20 | + | ||
| 21 | +} |
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/datapermission/core/service/dto/DeptDataPermissionRespDTO.java
0 → 100644
| 1 | +package cn.iocoder.yudao.adminserver.framework.datapermission.core.service.dto; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +import java.util.ArrayList; | ||
| 6 | +import java.util.HashSet; | ||
| 7 | +import java.util.List; | ||
| 8 | +import java.util.Set; | ||
| 9 | + | ||
| 10 | +/** | ||
| 11 | + * 部门的数据权限 Response DTO | ||
| 12 | + * | ||
| 13 | + * @author 芋道源码 | ||
| 14 | + */ | ||
| 15 | +@Data | ||
| 16 | +public class DeptDataPermissionRespDTO { | ||
| 17 | + | ||
| 18 | + /** | ||
| 19 | + * 是否可查看全部数据 | ||
| 20 | + */ | ||
| 21 | + private Boolean all; | ||
| 22 | + /** | ||
| 23 | + * 是否可查看自己的数据 | ||
| 24 | + */ | ||
| 25 | + private Boolean self; | ||
| 26 | + /** | ||
| 27 | + * 可查看的部门编号数组 | ||
| 28 | + */ | ||
| 29 | + private Set<Long> deptIds; | ||
| 30 | + | ||
| 31 | + public DeptDataPermissionRespDTO() { | ||
| 32 | + this.all = false; | ||
| 33 | + this.self = false; | ||
| 34 | + this.deptIds = new HashSet<>(); | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | +} |
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/framework/datapermission/core/service/impl/DeptDataPermissionServiceImpl.java
0 → 100644
| 1 | +package cn.iocoder.yudao.adminserver.framework.datapermission.core.service.impl; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 4 | +import cn.iocoder.yudao.adminserver.framework.datapermission.core.service.DeptDataPermissionService; | ||
| 5 | +import cn.iocoder.yudao.adminserver.framework.datapermission.core.service.dto.DeptDataPermissionRespDTO; | ||
| 6 | +import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.dept.SysDeptDO; | ||
| 7 | +import cn.iocoder.yudao.adminserver.modules.system.dal.dataobject.permission.SysRoleDO; | ||
| 8 | +import cn.iocoder.yudao.adminserver.modules.system.service.dept.SysDeptService; | ||
| 9 | +import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysRoleService; | ||
| 10 | +import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils; | ||
| 11 | +import cn.iocoder.yudao.framework.common.util.json.JsonUtils; | ||
| 12 | +import cn.iocoder.yudao.framework.security.core.LoginUser; | ||
| 13 | +import cn.iocoder.yudao.framework.security.core.enums.DataScopeEnum; | ||
| 14 | +import lombok.RequiredArgsConstructor; | ||
| 15 | +import lombok.extern.slf4j.Slf4j; | ||
| 16 | + | ||
| 17 | +import java.util.List; | ||
| 18 | +import java.util.Objects; | ||
| 19 | + | ||
| 20 | +/** | ||
| 21 | + * 基于部门的数据权限 Service 实现类 | ||
| 22 | + * | ||
| 23 | + * @author 芋道源码 | ||
| 24 | + */ | ||
| 25 | +@RequiredArgsConstructor | ||
| 26 | +@Slf4j | ||
| 27 | +public class DeptDataPermissionServiceImpl implements DeptDataPermissionService { | ||
| 28 | + | ||
| 29 | + /** | ||
| 30 | + * LoginUser 的 Context 缓存 Key | ||
| 31 | + */ | ||
| 32 | + private static final String CONTEXT_KEY = DeptDataPermissionServiceImpl.class.getSimpleName(); | ||
| 33 | + | ||
| 34 | + private final SysRoleService roleService; | ||
| 35 | + private final SysDeptService deptService; | ||
| 36 | + | ||
| 37 | + @Override | ||
| 38 | + public DeptDataPermissionRespDTO getDeptDataPermission(LoginUser loginUser) { | ||
| 39 | + // 判断是否 context 已经缓存 | ||
| 40 | + DeptDataPermissionRespDTO result = loginUser.getContext(CONTEXT_KEY, DeptDataPermissionRespDTO.class); | ||
| 41 | + if (result != null) { | ||
| 42 | + return result; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + // 创建 DeptDataPermissionRespDTO 对象 | ||
| 46 | + result = new DeptDataPermissionRespDTO(); | ||
| 47 | + List<SysRoleDO> roles = roleService.getRolesFromCache(loginUser.getRoleIds()); | ||
| 48 | + for (SysRoleDO role : roles) { | ||
| 49 | + // 为空时,跳过 | ||
| 50 | + if (role.getDataScope() == null) { | ||
| 51 | + continue; | ||
| 52 | + } | ||
| 53 | + // 情况一,ALL | ||
| 54 | + if (Objects.equals(role.getDataScope(), DataScopeEnum.ALL.getScope())) { | ||
| 55 | + result.setAll(true); | ||
| 56 | + continue; | ||
| 57 | + } | ||
| 58 | + // 情况二,DEPT_CUSTOM | ||
| 59 | + if (Objects.equals(role.getDataScope(), DataScopeEnum.DEPT_CUSTOM.getScope())) { | ||
| 60 | + CollUtil.addAll(result.getDeptIds(), role.getDataScopeDeptIds()); | ||
| 61 | + continue; | ||
| 62 | + } | ||
| 63 | + // 情况三,DEPT_ONLY | ||
| 64 | + if (Objects.equals(role.getDataScope(), DataScopeEnum.DEPT_ONLY.getScope())) { | ||
| 65 | + CollectionUtils.addIfNotNull(result.getDeptIds(), loginUser.getDeptId()); | ||
| 66 | + continue; | ||
| 67 | + } | ||
| 68 | + // 情况四,DEPT_DEPT_AND_CHILD | ||
| 69 | + if (Objects.equals(role.getDataScope(), DataScopeEnum.DEPT_AND_CHILD.getScope())) { | ||
| 70 | + List<SysDeptDO> depts = deptService.getDeptsByParentIdFromCache(loginUser.getDeptId(), true); | ||
| 71 | + CollUtil.addAll(result.getDeptIds(), CollectionUtils.convertList(depts, SysDeptDO::getId)); | ||
| 72 | + continue; | ||
| 73 | + } | ||
| 74 | + // 情况五,SELF | ||
| 75 | + if (Objects.equals(role.getDataScope(), DataScopeEnum.SELF.getScope())) { | ||
| 76 | + result.setSelf(true); | ||
| 77 | + continue; | ||
| 78 | + } | ||
| 79 | + // 未知情况,error log 即可 | ||
| 80 | + log.error("[getDeptDataPermission][LoginUser({}) role({}) 无法处理]", loginUser.getId(), JsonUtils.toJsonString(result)); | ||
| 81 | + } | ||
| 82 | + | ||
| 83 | + // 添加到缓存,并返回 | ||
| 84 | + loginUser.setContext(CONTEXT_KEY, result); | ||
| 85 | + return null; | ||
| 86 | + } | ||
| 87 | + | ||
| 88 | +} |
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/impl/SysAuthServiceImpl.java
| @@ -92,9 +92,7 @@ public class SysAuthServiceImpl implements SysAuthService { | @@ -92,9 +92,7 @@ public class SysAuthServiceImpl implements SysAuthService { | ||
| 92 | throw new UsernameNotFoundException(username); | 92 | throw new UsernameNotFoundException(username); |
| 93 | } | 93 | } |
| 94 | // 创建 LoginUser 对象 | 94 | // 创建 LoginUser 对象 |
| 95 | - LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user); | ||
| 96 | - loginUser.setPostIds(user.getPostIds()); | ||
| 97 | - return loginUser; | 95 | + return this.buildLoginUser(user); |
| 98 | } | 96 | } |
| 99 | 97 | ||
| 100 | @Override | 98 | @Override |
| @@ -107,9 +105,7 @@ public class SysAuthServiceImpl implements SysAuthService { | @@ -107,9 +105,7 @@ public class SysAuthServiceImpl implements SysAuthService { | ||
| 107 | this.createLoginLog(user.getUsername(), SysLoginLogTypeEnum.LOGIN_MOCK, SysLoginResultEnum.SUCCESS); | 105 | this.createLoginLog(user.getUsername(), SysLoginLogTypeEnum.LOGIN_MOCK, SysLoginResultEnum.SUCCESS); |
| 108 | 106 | ||
| 109 | // 创建 LoginUser 对象 | 107 | // 创建 LoginUser 对象 |
| 110 | - LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user); | ||
| 111 | - loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); // 获取用户角色列表 | ||
| 112 | - return loginUser; | 108 | + return this.buildLoginUser(user); |
| 113 | } | 109 | } |
| 114 | 110 | ||
| 115 | @Override | 111 | @Override |
| @@ -117,10 +113,9 @@ public class SysAuthServiceImpl implements SysAuthService { | @@ -117,10 +113,9 @@ public class SysAuthServiceImpl implements SysAuthService { | ||
| 117 | // 判断验证码是否正确 | 113 | // 判断验证码是否正确 |
| 118 | this.verifyCaptcha(reqVO.getUsername(), reqVO.getUuid(), reqVO.getCode()); | 114 | this.verifyCaptcha(reqVO.getUsername(), reqVO.getUuid(), reqVO.getCode()); |
| 119 | 115 | ||
| 120 | - // 使用账号密码,进行登录。 | 116 | + // 使用账号密码,进行登录 |
| 121 | LoginUser loginUser = this.login0(reqVO.getUsername(), reqVO.getPassword()); | 117 | LoginUser loginUser = this.login0(reqVO.getUsername(), reqVO.getPassword()); |
| 122 | - loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); // 获取用户角色列表 | ||
| 123 | - loginUser.setGroups(this.getUserPosts(loginUser.getPostIds())); | 118 | + |
| 124 | // 缓存登陆用户到 Redis 中,返回 sessionId 编号 | 119 | // 缓存登陆用户到 Redis 中,返回 sessionId 编号 |
| 125 | return userSessionCoreService.createUserSession(loginUser, userIp, userAgent); | 120 | return userSessionCoreService.createUserSession(loginUser, userIp, userAgent); |
| 126 | } | 121 | } |
| @@ -234,8 +229,7 @@ public class SysAuthServiceImpl implements SysAuthService { | @@ -234,8 +229,7 @@ public class SysAuthServiceImpl implements SysAuthService { | ||
| 234 | this.createLoginLog(user.getUsername(), SysLoginLogTypeEnum.LOGIN_SOCIAL, SysLoginResultEnum.SUCCESS); | 229 | this.createLoginLog(user.getUsername(), SysLoginLogTypeEnum.LOGIN_SOCIAL, SysLoginResultEnum.SUCCESS); |
| 235 | 230 | ||
| 236 | // 创建 LoginUser 对象 | 231 | // 创建 LoginUser 对象 |
| 237 | - LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user); | ||
| 238 | - loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); // 获取用户角色列表 | 232 | + LoginUser loginUser = this.buildLoginUser(user); |
| 239 | 233 | ||
| 240 | // 绑定社交用户(更新) | 234 | // 绑定社交用户(更新) |
| 241 | socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, userTypeEnum); | 235 | socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, userTypeEnum); |
| @@ -252,7 +246,6 @@ public class SysAuthServiceImpl implements SysAuthService { | @@ -252,7 +246,6 @@ public class SysAuthServiceImpl implements SysAuthService { | ||
| 252 | 246 | ||
| 253 | // 使用账号密码,进行登录。 | 247 | // 使用账号密码,进行登录。 |
| 254 | LoginUser loginUser = this.login0(reqVO.getUsername(), reqVO.getPassword()); | 248 | LoginUser loginUser = this.login0(reqVO.getUsername(), reqVO.getPassword()); |
| 255 | - loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); // 获取用户角色列表 | ||
| 256 | 249 | ||
| 257 | // 绑定社交用户(新增) | 250 | // 绑定社交用户(新增) |
| 258 | socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, userTypeEnum); | 251 | socialService.bindSocialUser(loginUser.getId(), reqVO.getType(), authUser, userTypeEnum); |
| @@ -305,15 +298,14 @@ public class SysAuthServiceImpl implements SysAuthService { | @@ -305,15 +298,14 @@ public class SysAuthServiceImpl implements SysAuthService { | ||
| 305 | return null; | 298 | return null; |
| 306 | } | 299 | } |
| 307 | // 刷新 LoginUser 缓存 | 300 | // 刷新 LoginUser 缓存 |
| 308 | - this.refreshLoginUserCache(token, loginUser); | ||
| 309 | - return loginUser; | 301 | + return this.refreshLoginUserCache(token, loginUser); |
| 310 | } | 302 | } |
| 311 | 303 | ||
| 312 | - private void refreshLoginUserCache(String token, LoginUser loginUser) { | 304 | + private LoginUser refreshLoginUserCache(String token, LoginUser loginUser) { |
| 313 | // 每 1/3 的 Session 超时时间,刷新 LoginUser 缓存 | 305 | // 每 1/3 的 Session 超时时间,刷新 LoginUser 缓存 |
| 314 | if (System.currentTimeMillis() - loginUser.getUpdateTime().getTime() < | 306 | if (System.currentTimeMillis() - loginUser.getUpdateTime().getTime() < |
| 315 | userSessionCoreService.getSessionTimeoutMillis() / 3) { | 307 | userSessionCoreService.getSessionTimeoutMillis() / 3) { |
| 316 | - return; | 308 | + return loginUser; |
| 317 | } | 309 | } |
| 318 | 310 | ||
| 319 | // 重新加载 SysUserDO 信息 | 311 | // 重新加载 SysUserDO 信息 |
| @@ -323,9 +315,18 @@ public class SysAuthServiceImpl implements SysAuthService { | @@ -323,9 +315,18 @@ public class SysAuthServiceImpl implements SysAuthService { | ||
| 323 | } | 315 | } |
| 324 | 316 | ||
| 325 | // 刷新 LoginUser 缓存 | 317 | // 刷新 LoginUser 缓存 |
| 318 | + LoginUser newLoginUser= this.buildLoginUser(user); | ||
| 319 | + userSessionCoreService.refreshUserSession(token, newLoginUser); | ||
| 320 | + return newLoginUser; | ||
| 321 | + } | ||
| 322 | + | ||
| 323 | + private LoginUser buildLoginUser(SysUserDO user) { | ||
| 324 | + LoginUser loginUser = SysAuthConvert.INSTANCE.convert(user); | ||
| 325 | + // 补全字段 | ||
| 326 | loginUser.setDeptId(user.getDeptId()); | 326 | loginUser.setDeptId(user.getDeptId()); |
| 327 | loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); | 327 | loginUser.setRoleIds(this.getUserRoleIds(loginUser.getId())); |
| 328 | - userSessionCoreService.refreshUserSession(token, loginUser); | 328 | + loginUser.setGroups(this.getUserPosts(user.getPostIds())); |
| 329 | + return loginUser; | ||
| 329 | } | 330 | } |
| 330 | 331 | ||
| 331 | } | 332 | } |
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/dept/impl/SysDeptServiceImpl.java
| @@ -169,9 +169,12 @@ public class SysDeptServiceImpl implements SysDeptService { | @@ -169,9 +169,12 @@ public class SysDeptServiceImpl implements SysDeptService { | ||
| 169 | 169 | ||
| 170 | @Override | 170 | @Override |
| 171 | public List<SysDeptDO> getDeptsByParentIdFromCache(Long parentId, boolean recursive) { | 171 | public List<SysDeptDO> getDeptsByParentIdFromCache(Long parentId, boolean recursive) { |
| 172 | - List<SysDeptDO> result = new ArrayList<>(); | 172 | + if (parentId == null) { |
| 173 | + return Collections.emptyList(); | ||
| 174 | + } | ||
| 175 | + List<SysDeptDO> result = new ArrayList<>(); // TODO 芋艿:待优化,新增缓存,避免每次遍历的计算 | ||
| 173 | // 递归,简单粗暴 | 176 | // 递归,简单粗暴 |
| 174 | - this.listDeptsByParentIdFromCache(result, parentId, | 177 | + this.getDeptsByParentIdFromCache(result, parentId, |
| 175 | recursive ? Integer.MAX_VALUE : 1, // 如果递归获取,则无限;否则,只递归 1 次 | 178 | recursive ? Integer.MAX_VALUE : 1, // 如果递归获取,则无限;否则,只递归 1 次 |
| 176 | parentDeptCache); | 179 | parentDeptCache); |
| 177 | return result; | 180 | return result; |
| @@ -185,8 +188,8 @@ public class SysDeptServiceImpl implements SysDeptService { | @@ -185,8 +188,8 @@ public class SysDeptServiceImpl implements SysDeptService { | ||
| 185 | * @param recursiveCount 递归次数 | 188 | * @param recursiveCount 递归次数 |
| 186 | * @param parentDeptMap 父部门 Map,使用缓存,避免变化 | 189 | * @param parentDeptMap 父部门 Map,使用缓存,避免变化 |
| 187 | */ | 190 | */ |
| 188 | - private void listDeptsByParentIdFromCache(List<SysDeptDO> result, Long parentId, int recursiveCount, | ||
| 189 | - Multimap<Long, SysDeptDO> parentDeptMap) { | 191 | + private void getDeptsByParentIdFromCache(List<SysDeptDO> result, Long parentId, int recursiveCount, |
| 192 | + Multimap<Long, SysDeptDO> parentDeptMap) { | ||
| 190 | // 递归次数为 0,结束! | 193 | // 递归次数为 0,结束! |
| 191 | if (recursiveCount == 0) { | 194 | if (recursiveCount == 0) { |
| 192 | return; | 195 | return; |
| @@ -198,7 +201,7 @@ public class SysDeptServiceImpl implements SysDeptService { | @@ -198,7 +201,7 @@ public class SysDeptServiceImpl implements SysDeptService { | ||
| 198 | } | 201 | } |
| 199 | result.addAll(depts); | 202 | result.addAll(depts); |
| 200 | // 继续递归 | 203 | // 继续递归 |
| 201 | - depts.forEach(dept -> listDeptsByParentIdFromCache(result, dept.getId(), | 204 | + depts.forEach(dept -> getDeptsByParentIdFromCache(result, dept.getId(), |
| 202 | recursiveCount - 1, parentDeptMap)); | 205 | recursiveCount - 1, parentDeptMap)); |
| 203 | } | 206 | } |
| 204 | 207 |
yudao-admin-server/src/main/java/cn/iocoder/yudao/adminserver/modules/system/service/permission/impl/SysRoleServiceImpl.java
| @@ -18,6 +18,7 @@ import cn.iocoder.yudao.adminserver.modules.system.enums.permission.SysRoleTypeE | @@ -18,6 +18,7 @@ import cn.iocoder.yudao.adminserver.modules.system.enums.permission.SysRoleTypeE | ||
| 18 | import cn.iocoder.yudao.adminserver.modules.system.mq.producer.permission.SysRoleProducer; | 18 | import cn.iocoder.yudao.adminserver.modules.system.mq.producer.permission.SysRoleProducer; |
| 19 | import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService; | 19 | import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysPermissionService; |
| 20 | import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysRoleService; | 20 | import cn.iocoder.yudao.adminserver.modules.system.service.permission.SysRoleService; |
| 21 | +import cn.iocoder.yudao.framework.security.core.enums.DataScopeEnum; | ||
| 21 | import com.google.common.annotations.VisibleForTesting; | 22 | import com.google.common.annotations.VisibleForTesting; |
| 22 | import com.google.common.collect.ImmutableMap; | 23 | import com.google.common.collect.ImmutableMap; |
| 23 | import lombok.extern.slf4j.Slf4j; | 24 | import lombok.extern.slf4j.Slf4j; |
| @@ -127,6 +128,7 @@ public class SysRoleServiceImpl implements SysRoleService { | @@ -127,6 +128,7 @@ public class SysRoleServiceImpl implements SysRoleService { | ||
| 127 | SysRoleDO role = SysRoleConvert.INSTANCE.convert(reqVO); | 128 | SysRoleDO role = SysRoleConvert.INSTANCE.convert(reqVO); |
| 128 | role.setType(SysRoleTypeEnum.CUSTOM.getType()); | 129 | role.setType(SysRoleTypeEnum.CUSTOM.getType()); |
| 129 | role.setStatus(CommonStatusEnum.ENABLE.getStatus()); | 130 | role.setStatus(CommonStatusEnum.ENABLE.getStatus()); |
| 131 | + role.setDataScope(DataScopeEnum.ALL.getScope()); // 默认可查看所有数据。原因是,可能一些项目不需要项目权限 | ||
| 130 | roleMapper.insert(role); | 132 | roleMapper.insert(role); |
| 131 | // 发送刷新消息 | 133 | // 发送刷新消息 |
| 132 | roleProducer.sendRoleRefreshMessage(); | 134 | roleProducer.sendRoleRefreshMessage(); |
yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/system/service/auth/SysAuthServiceImplTest.java
| @@ -89,7 +89,6 @@ public class SysAuthServiceImplTest extends BaseDbUnitTest { | @@ -89,7 +89,6 @@ public class SysAuthServiceImplTest extends BaseDbUnitTest { | ||
| 89 | LoginUser loginUser = (LoginUser) authService.loadUserByUsername(username); | 89 | LoginUser loginUser = (LoginUser) authService.loadUserByUsername(username); |
| 90 | // 校验 | 90 | // 校验 |
| 91 | AssertUtils.assertPojoEquals(user, loginUser, "updateTime"); | 91 | AssertUtils.assertPojoEquals(user, loginUser, "updateTime"); |
| 92 | - assertNull(loginUser.getRoleIds()); // 此时不会加载角色,所以是空的 | ||
| 93 | } | 92 | } |
| 94 | 93 | ||
| 95 | @Test | 94 | @Test |
yudao-admin-server/src/test/java/cn/iocoder/yudao/adminserver/modules/system/service/permission/SysRoleServiceTest.java
| @@ -133,11 +133,11 @@ public class SysRoleServiceTest extends BaseDbUnitTest { | @@ -133,11 +133,11 @@ public class SysRoleServiceTest extends BaseDbUnitTest { | ||
| 133 | 133 | ||
| 134 | //调用 | 134 | //调用 |
| 135 | Set<Long> deptIdSet = Arrays.asList(1L, 2L, 3L, 4L, 5L).stream().collect(Collectors.toSet()); | 135 | Set<Long> deptIdSet = Arrays.asList(1L, 2L, 3L, 4L, 5L).stream().collect(Collectors.toSet()); |
| 136 | - sysRoleService.updateRoleDataScope(roleId, DataScopeEnum.DEPT_CUSTOM.getScore(), deptIdSet); | 136 | + sysRoleService.updateRoleDataScope(roleId, DataScopeEnum.DEPT_CUSTOM.getScope(), deptIdSet); |
| 137 | 137 | ||
| 138 | //断言 | 138 | //断言 |
| 139 | SysRoleDO newRoleDO = roleMapper.selectById(roleId); | 139 | SysRoleDO newRoleDO = roleMapper.selectById(roleId); |
| 140 | - assertEquals(DataScopeEnum.DEPT_CUSTOM.getScore(), newRoleDO.getDataScope()); | 140 | + assertEquals(DataScopeEnum.DEPT_CUSTOM.getScope(), newRoleDO.getDataScope()); |
| 141 | 141 | ||
| 142 | Set<Long> newDeptIdSet = newRoleDO.getDataScopeDeptIds(); | 142 | Set<Long> newDeptIdSet = newRoleDO.getDataScopeDeptIds(); |
| 143 | assertTrue(deptIdSet.size() == newDeptIdSet.size()); | 143 | assertTrue(deptIdSet.size() == newDeptIdSet.size()); |
| @@ -242,7 +242,7 @@ public class SysRoleServiceTest extends BaseDbUnitTest { | @@ -242,7 +242,7 @@ public class SysRoleServiceTest extends BaseDbUnitTest { | ||
| 242 | o.setCode("code"); | 242 | o.setCode("code"); |
| 243 | o.setType(SysRoleTypeEnum.CUSTOM.getType()); | 243 | o.setType(SysRoleTypeEnum.CUSTOM.getType()); |
| 244 | o.setStatus(1); | 244 | o.setStatus(1); |
| 245 | - o.setDataScope(DataScopeEnum.ALL.getScore()); | 245 | + o.setDataScope(DataScopeEnum.ALL.getScope()); |
| 246 | }); | 246 | }); |
| 247 | roleMapper.insert(roleDO); | 247 | roleMapper.insert(roleDO); |
| 248 | 248 | ||
| @@ -293,7 +293,7 @@ public class SysRoleServiceTest extends BaseDbUnitTest { | @@ -293,7 +293,7 @@ public class SysRoleServiceTest extends BaseDbUnitTest { | ||
| 293 | o.setName(name); | 293 | o.setName(name); |
| 294 | o.setType(typeEnum.getType()); | 294 | o.setType(typeEnum.getType()); |
| 295 | o.setStatus(status); | 295 | o.setStatus(status); |
| 296 | - o.setDataScope(scopeEnum.getScore()); | 296 | + o.setDataScope(scopeEnum.getScope()); |
| 297 | o.setCode(code); | 297 | o.setCode(code); |
| 298 | }); | 298 | }); |
| 299 | return roleDO; | 299 | return roleDO; |
yudao-dependencies/pom.xml
| @@ -370,6 +370,12 @@ | @@ -370,6 +370,12 @@ | ||
| 370 | </dependency> | 370 | </dependency> |
| 371 | 371 | ||
| 372 | <dependency> | 372 | <dependency> |
| 373 | + <groupId>cn.iocoder.boot</groupId> | ||
| 374 | + <artifactId>yudao-spring-boot-starter-data-permission</artifactId> | ||
| 375 | + <version>${revision}</version> | ||
| 376 | + </dependency> | ||
| 377 | + | ||
| 378 | + <dependency> | ||
| 373 | <groupId>org.projectlombok</groupId> | 379 | <groupId>org.projectlombok</groupId> |
| 374 | <artifactId>lombok</artifactId> | 380 | <artifactId>lombok</artifactId> |
| 375 | <version>${lombok.version}</version> | 381 | <version>${lombok.version}</version> |
yudao-framework/yudao-spring-boot-starter-data-permission/src/main/java/cn/iocoder/yudao/framework/datapermission/config/DataPermissionAutoConfiguration.java
| @@ -5,11 +5,18 @@ import cn.iocoder.yudao.framework.datapermission.core.db.DataPermissionDatabaseI | @@ -5,11 +5,18 @@ import cn.iocoder.yudao.framework.datapermission.core.db.DataPermissionDatabaseI | ||
| 5 | import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule; | 5 | import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRule; |
| 6 | import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRuleFactory; | 6 | import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRuleFactory; |
| 7 | import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRuleFactoryImpl; | 7 | import cn.iocoder.yudao.framework.datapermission.core.rule.DataPermissionRuleFactoryImpl; |
| 8 | +import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils; | ||
| 9 | +import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; | ||
| 8 | import org.springframework.context.annotation.Bean; | 10 | import org.springframework.context.annotation.Bean; |
| 9 | import org.springframework.context.annotation.Configuration; | 11 | import org.springframework.context.annotation.Configuration; |
| 10 | 12 | ||
| 11 | import java.util.List; | 13 | import java.util.List; |
| 12 | 14 | ||
| 15 | +/** | ||
| 16 | + * 数据全新啊的自动配置类 | ||
| 17 | + * | ||
| 18 | + * @author 芋道源码 | ||
| 19 | + */ | ||
| 13 | @Configuration | 20 | @Configuration |
| 14 | public class DataPermissionAutoConfiguration { | 21 | public class DataPermissionAutoConfiguration { |
| 15 | 22 | ||
| @@ -19,9 +26,15 @@ public class DataPermissionAutoConfiguration { | @@ -19,9 +26,15 @@ public class DataPermissionAutoConfiguration { | ||
| 19 | } | 26 | } |
| 20 | 27 | ||
| 21 | @Bean | 28 | @Bean |
| 22 | - public DataPermissionDatabaseInterceptor dataPermissionDatabaseInterceptor(List<DataPermissionRule> rules) { | 29 | + public DataPermissionDatabaseInterceptor dataPermissionDatabaseInterceptor(MybatisPlusInterceptor interceptor, |
| 30 | + List<DataPermissionRule> rules) { | ||
| 31 | + // 创建 DataPermissionDatabaseInterceptor 拦截器 | ||
| 23 | DataPermissionRuleFactory ruleFactory = dataPermissionRuleFactory(rules); | 32 | DataPermissionRuleFactory ruleFactory = dataPermissionRuleFactory(rules); |
| 24 | - return new DataPermissionDatabaseInterceptor(ruleFactory); | 33 | + DataPermissionDatabaseInterceptor inner = new DataPermissionDatabaseInterceptor(ruleFactory); |
| 34 | + // 添加到 interceptor 中 | ||
| 35 | + // 需要加在首个,主要是为了在分页插件前面。这个是 MyBatis Plus 的规定 | ||
| 36 | + MyBatisUtils.addInterceptor(interceptor, inner, 0); | ||
| 37 | + return inner; | ||
| 25 | } | 38 | } |
| 26 | 39 | ||
| 27 | @Bean | 40 | @Bean |
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/LoginUser.java
| 1 | package cn.iocoder.yudao.framework.security.core; | 1 | package cn.iocoder.yudao.framework.security.core; |
| 2 | 2 | ||
| 3 | +import cn.hutool.core.map.MapUtil; | ||
| 3 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; | 4 | import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum; |
| 4 | import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; | 5 | import cn.iocoder.yudao.framework.common.enums.UserTypeEnum; |
| 5 | import com.fasterxml.jackson.annotation.JsonIgnore; | 6 | import com.fasterxml.jackson.annotation.JsonIgnore; |
| @@ -29,10 +30,6 @@ public class LoginUser implements UserDetails { | @@ -29,10 +30,6 @@ public class LoginUser implements UserDetails { | ||
| 29 | */ | 30 | */ |
| 30 | private Integer userType; | 31 | private Integer userType; |
| 31 | /** | 32 | /** |
| 32 | - * 角色编号数组 | ||
| 33 | - */ | ||
| 34 | - private Set<Long> roleIds; | ||
| 35 | - /** | ||
| 36 | * 最后更新时间 | 33 | * 最后更新时间 |
| 37 | */ | 34 | */ |
| 38 | private Date updateTime; | 35 | private Date updateTime; |
| @@ -56,7 +53,10 @@ public class LoginUser implements UserDetails { | @@ -56,7 +53,10 @@ public class LoginUser implements UserDetails { | ||
| 56 | 53 | ||
| 57 | // ========== UserTypeEnum.ADMIN 独有字段 ========== | 54 | // ========== UserTypeEnum.ADMIN 独有字段 ========== |
| 58 | // TODO 芋艿:可以通过定义一个 Map<String, String> exts 的方式,去除管理员的字段。不过这样会导致系统比较复杂,所以暂时不去掉先; | 55 | // TODO 芋艿:可以通过定义一个 Map<String, String> exts 的方式,去除管理员的字段。不过这样会导致系统比较复杂,所以暂时不去掉先; |
| 59 | - | 56 | + /** |
| 57 | + * 角色编号数组 | ||
| 58 | + */ | ||
| 59 | + private Set<Long> roleIds; | ||
| 60 | /** | 60 | /** |
| 61 | * 部门编号 | 61 | * 部门编号 |
| 62 | */ | 62 | */ |
| @@ -71,6 +71,15 @@ public class LoginUser implements UserDetails { | @@ -71,6 +71,15 @@ public class LoginUser implements UserDetails { | ||
| 71 | // TODO jason:这个字段,改成 postCodes 明确更好哈 | 71 | // TODO jason:这个字段,改成 postCodes 明确更好哈 |
| 72 | private List<String> groups; | 72 | private List<String> groups; |
| 73 | 73 | ||
| 74 | + // ========== 上下文 ========== | ||
| 75 | + /** | ||
| 76 | + * 上下文字段,不进行持久化 | ||
| 77 | + * | ||
| 78 | + * 1. 用于基于 LoginUser 维度的临时缓存 | ||
| 79 | + */ | ||
| 80 | + @JsonIgnore | ||
| 81 | + private Map<String, Object> context; | ||
| 82 | + | ||
| 74 | @Override | 83 | @Override |
| 75 | @JsonIgnore// 避免序列化 | 84 | @JsonIgnore// 避免序列化 |
| 76 | public String getPassword() { | 85 | public String getPassword() { |
| @@ -115,4 +124,17 @@ public class LoginUser implements UserDetails { | @@ -115,4 +124,17 @@ public class LoginUser implements UserDetails { | ||
| 115 | return true; // 返回 true,不依赖 Spring Security 判断 | 124 | return true; // 返回 true,不依赖 Spring Security 判断 |
| 116 | } | 125 | } |
| 117 | 126 | ||
| 127 | + // ========== 上下文 ========== | ||
| 128 | + | ||
| 129 | + public void setContext(String key, Object value) { | ||
| 130 | + if (context == null) { | ||
| 131 | + context = new HashMap<>(); | ||
| 132 | + } | ||
| 133 | + context.put(key, value); | ||
| 134 | + } | ||
| 135 | + | ||
| 136 | + public <T> T getContext(String key, Class<T> type) { | ||
| 137 | + return MapUtil.get(context, key, type); | ||
| 138 | + } | ||
| 139 | + | ||
| 118 | } | 140 | } |
yudao-framework/yudao-spring-boot-starter-security/src/main/java/cn/iocoder/yudao/framework/security/core/enums/DataScopeEnum.java
| @@ -15,14 +15,16 @@ import lombok.Getter; | @@ -15,14 +15,16 @@ import lombok.Getter; | ||
| 15 | public enum DataScopeEnum { | 15 | public enum DataScopeEnum { |
| 16 | 16 | ||
| 17 | ALL(1), // 全部数据权限 | 17 | ALL(1), // 全部数据权限 |
| 18 | + | ||
| 18 | DEPT_CUSTOM(2), // 指定部门数据权限 | 19 | DEPT_CUSTOM(2), // 指定部门数据权限 |
| 19 | DEPT_ONLY(3), // 部门数据权限 | 20 | DEPT_ONLY(3), // 部门数据权限 |
| 20 | DEPT_AND_CHILD(4), // 部门及以下数据权限 | 21 | DEPT_AND_CHILD(4), // 部门及以下数据权限 |
| 21 | - DEPT_SELF(5); // 仅本人数据权限 | 22 | + |
| 23 | + SELF(5); // 仅本人数据权限 | ||
| 22 | 24 | ||
| 23 | /** | 25 | /** |
| 24 | * 范围 | 26 | * 范围 |
| 25 | */ | 27 | */ |
| 26 | - private final Integer score; | 28 | + private final Integer scope; |
| 27 | 29 | ||
| 28 | } | 30 | } |
更新日志.md
| @@ -29,6 +29,7 @@ | @@ -29,6 +29,7 @@ | ||
| 29 | * 【新增】多租户,支持 Web、Security、Job、MQ、Async、DB、Redis 组件 | 29 | * 【新增】多租户,支持 Web、Security、Job、MQ、Async、DB、Redis 组件 |
| 30 | * 【新增】数据权限,内置基于部门过滤的规则 | 30 | * 【新增】数据权限,内置基于部门过滤的规则 |
| 31 | * 【新增】用户前台的昵称、头像的修改 | 31 | * 【新增】用户前台的昵称、头像的修改 |
| 32 | +* 【优化】管理后台的登陆成功后,LoginUser 使用统一方法补全信息 | ||
| 32 | 33 | ||
| 33 | ### 🐞 Bug Fixes | 34 | ### 🐞 Bug Fixes |
| 34 | 35 |