Merge branch 'master-jdk17' of https://gitee.com/zhijiantianya/ruoyi-vue-pro
# Conflicts: # pom.xml # yudao-dependencies/pom.xml # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/BpmModelController.java # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModeImportReqVO.java # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelSaveReqVO.java # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/definition/vo/model/BpmModelUpdateReqVO.java # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/controller/admin/task/BpmTaskController.java # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptLeaderStrategy.java # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateDeptMemberStrategy.java # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateGroupStrategy.java # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidatePostStrategy.java # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateRoleStrategy.java # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateStartUserSelectStrategy.java # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/candidate/strategy/BpmTaskCandidateUserStrategy.java # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/framework/flowable/core/listener/BpmTaskEventListener.java # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelService.java # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmModelServiceImpl.java # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/definition/BpmProcessDefinitionServiceImpl.java # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/message/BpmMessageService.java # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmActivityServiceImpl.java # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceService.java # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmProcessInstanceServiceImpl.java # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskService.java # yudao-module-bpm/yudao-module-bpm-biz/src/main/java/cn/iocoder/yudao/module/bpm/service/task/BpmTaskServiceImpl.java # yudao-module-crm/yudao-module-crm-biz/src/main/java/cn/iocoder/yudao/module/crm/framework/permission/core/aop/CrmPermissionAspect.java # yudao-module-system/yudao-module-system-biz/src/main/java/cn/iocoder/yudao/module/system/api/user/AdminUserApiImpl.java # yudao-server/pom.xml
This commit is contained in:
@@ -3,18 +3,16 @@ package cn.iocoder.yudao.module.system.api.user;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjUtil;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.datapermission.core.annotation.DataPermission;
|
||||
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
|
||||
import cn.iocoder.yudao.module.system.service.dept.DeptService;
|
||||
import cn.iocoder.yudao.module.system.service.user.AdminUserService;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
|
||||
@@ -40,21 +38,13 @@ public class AdminUserApiImpl implements AdminUserApi {
|
||||
@Override
|
||||
public List<AdminUserRespDTO> getUserListBySubordinate(Long id) {
|
||||
// 1.1 获取用户负责的部门
|
||||
AdminUserDO user = userService.getUser(id);
|
||||
if (user == null) {
|
||||
List<DeptDO> depts = deptService.getDeptListByLeaderUserId(id);
|
||||
if (CollUtil.isEmpty(depts)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
ArrayList<Long> deptIds = new ArrayList<>();
|
||||
DeptDO dept = deptService.getDept(user.getDeptId());
|
||||
if (dept == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
if (ObjUtil.notEqual(dept.getLeaderUserId(), id)) { // 校验为负责人
|
||||
return Collections.emptyList();
|
||||
}
|
||||
deptIds.add(dept.getId());
|
||||
// 1.2 获取所有子部门
|
||||
List<DeptDO> childDeptList = deptService.getChildDeptList(dept.getId());
|
||||
Set<Long> deptIds = convertSet(depts, DeptDO::getId);
|
||||
List<DeptDO> childDeptList = deptService.getChildDeptList(deptIds);
|
||||
if (CollUtil.isNotEmpty(childDeptList)) {
|
||||
deptIds.addAll(convertSet(childDeptList, DeptDO::getId));
|
||||
}
|
||||
@@ -66,6 +56,7 @@ public class AdminUserApiImpl implements AdminUserApi {
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataPermission(enable = false) // 禁用数据权限。原因是,一般基于指定 id 的 API 查询,都是数据拼接为主
|
||||
public List<AdminUserRespDTO> getUserList(Collection<Long> ids) {
|
||||
List<AdminUserDO> users = userService.getUserList(ids);
|
||||
return BeanUtils.toBean(users, AdminUserRespDTO.class);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
package cn.iocoder.yudao.module.system.dal.dataobject.oauth2;
|
||||
|
||||
import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
|
||||
import cn.iocoder.yudao.framework.tenant.core.db.TenantBaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
@@ -24,7 +24,7 @@ import java.util.List;
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Accessors(chain = true)
|
||||
public class OAuth2RefreshTokenDO extends BaseDO {
|
||||
public class OAuth2RefreshTokenDO extends TenantBaseDO {
|
||||
|
||||
/**
|
||||
* 编号,数据库字典
|
||||
|
@@ -30,4 +30,8 @@ public interface DeptMapper extends BaseMapperX<DeptDO> {
|
||||
return selectList(DeptDO::getParentId, parentIds);
|
||||
}
|
||||
|
||||
default List<DeptDO> selectListByLeaderUserId(Long id) {
|
||||
return selectList(DeptDO::getLeaderUserId, id);
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -2,6 +2,7 @@ package cn.iocoder.yudao.module.system.dal.mysql.oauth2;
|
||||
|
||||
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2RefreshTokenDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
@@ -13,6 +14,7 @@ public interface OAuth2RefreshTokenMapper extends BaseMapperX<OAuth2RefreshToken
|
||||
.eq(OAuth2RefreshTokenDO::getRefreshToken, refreshToken));
|
||||
}
|
||||
|
||||
@TenantIgnore // 获取 token 的时候,需要忽略租户编号。原因是:一些场景下,可能不会传递 tenant-id 请求头,例如说文件上传、积木报表等等
|
||||
default OAuth2RefreshTokenDO selectByRefreshToken(String refreshToken) {
|
||||
return selectOne(OAuth2RefreshTokenDO::getRefreshToken, refreshToken);
|
||||
}
|
||||
|
@@ -5,10 +5,7 @@ import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqV
|
||||
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptSaveReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* 部门 Service 接口
|
||||
@@ -80,7 +77,25 @@ public interface DeptService {
|
||||
* @param id 部门编号
|
||||
* @return 子部门列表
|
||||
*/
|
||||
List<DeptDO> getChildDeptList(Long id);
|
||||
default List<DeptDO> getChildDeptList(Long id) {
|
||||
return getChildDeptList(Collections.singleton(id));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获得指定部门的所有子部门
|
||||
*
|
||||
* @param ids 部门编号数组
|
||||
* @return 子部门列表
|
||||
*/
|
||||
List<DeptDO> getChildDeptList(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* 获得指定领导者的部门列表
|
||||
*
|
||||
* @param id 领导者编号
|
||||
* @return 部门列表
|
||||
*/
|
||||
List<DeptDO> getDeptListByLeaderUserId(Long id);
|
||||
|
||||
/**
|
||||
* 获得所有子部门,从缓存中
|
||||
|
@@ -170,10 +170,10 @@ public class DeptServiceImpl implements DeptService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DeptDO> getChildDeptList(Long id) {
|
||||
public List<DeptDO> getChildDeptList(Collection<Long> ids) {
|
||||
List<DeptDO> children = new LinkedList<>();
|
||||
// 遍历每一层
|
||||
Collection<Long> parentIds = Collections.singleton(id);
|
||||
Collection<Long> parentIds = ids;
|
||||
for (int i = 0; i < Short.MAX_VALUE; i++) { // 使用 Short.MAX_VALUE 避免 bug 场景下,存在死循环
|
||||
// 查询当前层,所有的子部门
|
||||
List<DeptDO> depts = deptMapper.selectListByParentId(parentIds);
|
||||
@@ -188,6 +188,11 @@ public class DeptServiceImpl implements DeptService {
|
||||
return children;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<DeptDO> getDeptListByLeaderUserId(Long id) {
|
||||
return deptMapper.selectListByLeaderUserId(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
@DataPermission(enable = false) // 禁用数据权限,避免建立不正确的缓存
|
||||
@Cacheable(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST, key = "#id")
|
||||
|
@@ -9,8 +9,10 @@ import cn.iocoder.yudao.framework.common.enums.UserTypeEnum;
|
||||
import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
|
||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||
import cn.iocoder.yudao.framework.security.core.LoginUser;
|
||||
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
|
||||
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
|
||||
import cn.iocoder.yudao.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
|
||||
import cn.iocoder.yudao.module.system.dal.dataobject.oauth2.OAuth2ClientDO;
|
||||
@@ -105,8 +107,18 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
|
||||
return accessTokenDO;
|
||||
}
|
||||
|
||||
// 获取不到,从 MySQL 中获取
|
||||
// 获取不到,从 MySQL 中获取访问令牌
|
||||
accessTokenDO = oauth2AccessTokenMapper.selectByAccessToken(accessToken);
|
||||
if (accessTokenDO == null) {
|
||||
// 特殊:从 MySQL 中获取刷新令牌。原因:解决部分场景不方便刷新访问令牌场景
|
||||
// 例如说,积木报表只允许传递 token,不允许传递 refresh_token,导致无法刷新访问令牌
|
||||
// 再例如说,前端 WebSocket 的 token 直接跟在 url 上,无法传递 refresh_token
|
||||
OAuth2RefreshTokenDO refreshTokenDO = oauth2RefreshTokenMapper.selectByRefreshToken(accessToken);
|
||||
if (refreshTokenDO != null && !DateUtils.isExpired(refreshTokenDO.getExpiresTime())) {
|
||||
accessTokenDO = convertToAccessToken(refreshTokenDO);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果在 MySQL 存在,则往 Redis 中写入
|
||||
if (accessTokenDO != null && !DateUtils.isExpired(accessTokenDO.getExpiresTime())) {
|
||||
oauth2AccessTokenRedisDAO.set(accessTokenDO);
|
||||
@@ -169,6 +181,14 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
|
||||
return refreshToken;
|
||||
}
|
||||
|
||||
private OAuth2AccessTokenDO convertToAccessToken(OAuth2RefreshTokenDO refreshTokenDO) {
|
||||
OAuth2AccessTokenDO accessTokenDO = BeanUtils.toBean(refreshTokenDO, OAuth2AccessTokenDO.class)
|
||||
.setAccessToken(refreshTokenDO.getRefreshToken());
|
||||
TenantUtils.execute(refreshTokenDO.getTenantId(),
|
||||
() -> accessTokenDO.setUserInfo(buildUserInfo(refreshTokenDO.getUserId(), refreshTokenDO.getUserType())));
|
||||
return accessTokenDO;
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载用户信息,方便 {@link cn.iocoder.yudao.framework.security.core.LoginUser} 获取到昵称、部门等信息
|
||||
*
|
||||
|
@@ -335,6 +335,7 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
|
||||
/**
|
||||
* 获得部门条件:查询指定部门的子部门编号们,包括自身
|
||||
*
|
||||
* @param deptId 部门编号
|
||||
* @return 部门编号集合
|
||||
*/
|
||||
|
@@ -158,10 +158,11 @@ public class OAuth2TokenServiceImplTest extends BaseDbAndRedisUnitTest {
|
||||
.setAccessTokenValiditySeconds(30);
|
||||
when(oauth2ClientService.validOAuthClientFromCache(eq(clientId))).thenReturn(clientDO);
|
||||
// mock 数据(访问令牌)
|
||||
OAuth2RefreshTokenDO refreshTokenDO = randomPojo(OAuth2RefreshTokenDO.class)
|
||||
.setRefreshToken(refreshToken).setClientId(clientId)
|
||||
.setExpiresTime(LocalDateTime.now().plusDays(1))
|
||||
.setUserType(UserTypeEnum.ADMIN.getValue());
|
||||
OAuth2RefreshTokenDO refreshTokenDO = randomPojo(OAuth2RefreshTokenDO.class, o ->
|
||||
o.setRefreshToken(refreshToken).setClientId(clientId)
|
||||
.setExpiresTime(LocalDateTime.now().plusDays(1))
|
||||
.setUserType(UserTypeEnum.ADMIN.getValue())
|
||||
.setTenantId(TenantContextHolder.getTenantId()));
|
||||
oauth2RefreshTokenMapper.insert(refreshTokenDO);
|
||||
// mock 数据(访问令牌)
|
||||
OAuth2AccessTokenDO accessTokenDO = randomPojo(OAuth2AccessTokenDO.class).setRefreshToken(refreshToken)
|
||||
@@ -231,6 +232,22 @@ public class OAuth2TokenServiceImplTest extends BaseDbAndRedisUnitTest {
|
||||
new ErrorCode(401, "访问令牌已过期"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckAccessToken_refreshToken() {
|
||||
// mock 数据(访问令牌)
|
||||
OAuth2RefreshTokenDO refreshTokenDO = randomPojo(OAuth2RefreshTokenDO.class)
|
||||
.setExpiresTime(LocalDateTime.now().plusDays(1));
|
||||
oauth2RefreshTokenMapper.insert(refreshTokenDO);
|
||||
// 准备参数
|
||||
String accessToken = refreshTokenDO.getRefreshToken();
|
||||
|
||||
// 调研,并断言
|
||||
OAuth2AccessTokenDO result = oauth2TokenService.getAccessToken(accessToken);
|
||||
// 断言
|
||||
assertPojoEquals(refreshTokenDO, result, "expiresTime", "createTime", "updateTime", "deleted",
|
||||
"creator", "updater");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCheckAccessToken_success() {
|
||||
// mock 数据(访问令牌)
|
||||
|
@@ -473,7 +473,7 @@ CREATE TABLE IF NOT EXISTS "system_oauth2_access_token" (
|
||||
"updater" varchar DEFAULT '',
|
||||
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
"deleted" bit NOT NULL DEFAULT FALSE,
|
||||
"tenant_id" bigint NOT NULL,
|
||||
"tenant_id" bigint not null,
|
||||
PRIMARY KEY ("id")
|
||||
) COMMENT 'OAuth2 访问令牌';
|
||||
|
||||
@@ -491,6 +491,7 @@ CREATE TABLE IF NOT EXISTS "system_oauth2_refresh_token" (
|
||||
"updater" varchar DEFAULT '',
|
||||
"update_time" datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
"deleted" bit NOT NULL DEFAULT FALSE,
|
||||
"tenant_id" bigint not null default '0',
|
||||
PRIMARY KEY ("id")
|
||||
) COMMENT 'OAuth2 刷新令牌';
|
||||
|
||||
|
Reference in New Issue
Block a user