1、sonarqube质量修复;2、短信日志导出请求url修正;3、新增支持删除机构、部门同时删除下属用户;4、token支持存deptId;

This commit is contained in:
gaoqr
2024-10-10 16:37:28 +08:00
parent c0cc38c691
commit 7e53f34a6a
18 changed files with 197 additions and 13 deletions
@@ -31,6 +31,12 @@ public class LoginUser {
* 组织编号
*/
private Long organId;
/**
* 部门编号
*/
private Long deptId;
/**
* 授权范围
*/
@@ -55,4 +55,8 @@ public class LoginUser {
*/
private Boolean isSupAdmin;
/**
* 部门编号
*/
private Long deptId;
}
@@ -123,7 +123,7 @@ public class TokenAuthenticationFilter implements GlobalFilter, Ordered {
.setOrganId(tokenInfo.getOrganId()).setScopes(tokenInfo.getScopes())
.setLarge(tokenInfo.getLarge()).setDbNo(tokenInfo.getDbNo()).setTableNo(tokenInfo.getTableNo())
.setDataCode(tokenInfo.getDataCode()).setIsSupAdmin(tokenInfo.getIsSupAdmin())
.setNickname(tokenInfo.getNickname());
.setNickname(tokenInfo.getNickname()).setDeptId(tokenInfo.getDeptId());
}
@Override
@@ -1,6 +1,6 @@
package com.cf.imes.module.executor.service.order;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.CollUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch.core.*;
@@ -211,7 +211,7 @@ public class OrderInputProcessor {
try {
SearchResponse<?> search = elasticsearchClient.search(builder.build(), Object.class);
List<? extends Hit<?>> hits = search.hits().hits();
if (CollectionUtil.isNotEmpty(hits)) {
if (CollUtil.isNotEmpty(hits)) {
return hits.stream().map(Hit::id).collect(Collectors.toList());
}
return new ArrayList<>();
@@ -35,4 +35,6 @@ public class OAuth2AccessTokenCheckRespDTO implements Serializable {
@Schema(description = "是否超级管理员")
private Boolean isSupAdmin;
@Schema(description = "部门编号", example = "1")
private Long deptId;
}
@@ -64,6 +64,7 @@ public class ErrorCodeConstants {
public static final ErrorCode DEPT_EXISTS_USER = new ErrorCode(1_002_004_005, "部门中存在员工,无法删除");
public static final ErrorCode DEPT_NOT_ENABLE = new ErrorCode(1_002_004_006, "部门({})不处于开启状态,不允许选择");
public static final ErrorCode DEPT_PARENT_IS_CHILD = new ErrorCode(1_002_004_007, "不能设置自己的子部门为父部门");
public static final ErrorCode DEPT_USER_OPER_NOT_ALLOW = new ErrorCode(1_002_015_008, "不允许操作用户自身部门");
// ========== 岗位模块 1-002-005-000 ==========
public static final ErrorCode POST_NOT_FOUND = new ErrorCode(1_002_005_000, "当前岗位不存在");
@@ -124,6 +125,7 @@ public class ErrorCodeConstants {
public static final ErrorCode ORGAN_WEBSITE_DUPLICATE = new ErrorCode(1_002_015_005, "域名为【{}】的组织已存在");
public static final ErrorCode ORGAN_DATA_CODE_NOT_EXISTS = new ErrorCode(1_002_015_006, "组织未配置数据源标识");
public static final ErrorCode ORGAN_ALREADY_EXISTS = new ErrorCode(1_002_015_007, "该新增组织已授权机台数量无需重复新增!");
public static final ErrorCode ORGAN_USER_OPER_NOT_ALLOW = new ErrorCode(1_002_015_008, "不允许操作用户自身组织");
// ========== 组织套餐 1-002-016-000 ==========
public static final ErrorCode TENANT_PACKAGE_NOT_EXISTS = new ErrorCode(1_002_016_000, "组织套餐不存在");
@@ -44,7 +44,7 @@ public class SmsLogController {
return success(BeanUtils.toBean(pageResult, SmsLogRespVO.class));
}
@GetMapping("/export-excel")
@GetMapping("/export")
@Operation(summary = "导出短信日志 Excel")
@PreAuthorize("@ss.hasPermission('system:sms-log:export')")
@OperateLog(type = EXPORT)
@@ -95,4 +95,6 @@ public class OAuth2AccessTokenDO extends BaseDO {
* 是否超级管理员
*/
private Boolean isSupAdmin;
private Long deptId;
}
@@ -183,6 +183,23 @@ public interface AdminUserMapper extends BaseMapperX<AdminUserDO> {
@Delete("DELETE FROM system_users WHERE id = #{id}")
int physicalDeleteById(@Param("id") Long id);
/**
* 查询机构下的所有用户
*
* @param organId
* @return
*/
@Select("SELECT ID FROM system_users WHERE organ_id = #{organId}")
List<Long> selectAllOrganUsers(@Param("organId") Long organId);
/**
* 查询部门下的所有用户
*
* @param deptId
* @return
*/
@Select("SELECT ID FROM system_users WHERE dept_id = #{deptId}")
List<Long> selectAllDeptUsers(@Param("deptId") Long deptId);
List<AdminUserDO> selectUserDataSource(@Param("filed") String filed,@Param("organId") Long organId,@Param("nameList") List<String> nameList);
@@ -139,7 +139,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
throw exception(ORGAN_DATA_CODE_NOT_EXISTS);
}
// 创建 Token 令牌,记录登录日志
return createTokenAfterLoginSuccess(user.getId(), reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME,organ.getLarge(), dataSourceCode, user.getOrganId(), user.getNickname());
return createTokenAfterLoginSuccess(user, reqVO.getUsername(), LoginLogTypeEnum.LOGIN_USERNAME, dataSourceCode);
}
@Override
@@ -200,7 +200,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
}
// 创建 Token 令牌,记录登录日志
return createTokenAfterLoginSuccess(user.getId(), reqVO.getMobile(), LoginLogTypeEnum.LOGIN_MOBILE, organ.getLarge(), dataSourceCode, organId, user.getNickname());
return createTokenAfterLoginSuccess(user, reqVO.getMobile(), LoginLogTypeEnum.LOGIN_MOBILE, dataSourceCode);
}
private void createLoginLog(Long userId, String username,
@@ -245,7 +245,7 @@ public class AdminAuthServiceImpl implements AdminAuthService {
}
// 创建 Token 令牌,记录登录日志
return createTokenAfterLoginSuccess(user.getId(), user.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL, organ.getLarge(), dataSourceCode, organId, user.getNickname());
return createTokenAfterLoginSuccess(user, user.getUsername(), LoginLogTypeEnum.LOGIN_SOCIAL, dataSourceCode);
}
@VisibleForTesting
@@ -277,6 +277,24 @@ public class AdminAuthServiceImpl implements AdminAuthService {
return AuthConvert.INSTANCE.convert(accessTokenDO);
}
/**
* 登陆成功后创建token
*
* @param user
* @param username
* @param logType
* @param dataCode
* @return
*/
private AuthLoginRespVO createTokenAfterLoginSuccess(AdminUserDO user, String username, LoginLogTypeEnum logType, String dataCode) {
// 插入登陆日志
createLoginLog(user.getId(), username, logType, LoginResultEnum.SUCCESS);
// 创建访问令牌
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken(user, getUserType().getValue(), OAuth2ClientConstants.CLIENT_ID_DEFAULT, dataCode);
// 构建返回结果
return AuthConvert.INSTANCE.convert(accessTokenDO);
}
@Override
public AuthLoginRespVO refreshToken(String refreshToken) {
OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.refreshAccessToken(refreshToken, OAuth2ClientConstants.CLIENT_ID_DEFAULT);
@@ -6,16 +6,20 @@ import com.cf.imes.framework.common.enums.CommonStatusEnum;
import com.cf.imes.framework.common.exception.util.ServiceExceptionUtil;
import com.cf.imes.framework.common.util.object.BeanUtils;
import com.cf.imes.framework.datapermission.core.annotation.DataPermission;
import com.cf.imes.framework.security.core.LoginUser;
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
import com.cf.imes.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
import com.cf.imes.module.system.controller.admin.dept.vo.dept.DeptSaveReqVO;
import com.cf.imes.module.system.dal.dataobject.dept.DeptDO;
import com.cf.imes.module.system.dal.mysql.dept.DeptMapper;
import com.cf.imes.module.system.dal.redis.RedisKeyConstants;
import com.cf.imes.module.system.enums.ErrorCodeConstants;
import com.cf.imes.module.system.service.user.AdminUserService;
import com.google.common.annotations.VisibleForTesting;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
@@ -24,6 +28,7 @@ import java.util.*;
import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.cf.imes.framework.common.util.collection.CollectionUtils.convertSet;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.DEPT_USER_OPER_NOT_ALLOW;
/**
* 部门 Service 实现类
@@ -38,6 +43,10 @@ public class DeptServiceImpl implements DeptService {
@Resource
private DeptMapper deptMapper;
@Resource
@Lazy // 延迟,避免循环依赖报错
private AdminUserService userService;
@Override
@CacheEvict(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST,
allEntries = true) // allEntries 清空所有缓存,因为操作一个部门,涉及到多个缓存
@@ -79,6 +88,8 @@ public class DeptServiceImpl implements DeptService {
@CacheEvict(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST,
allEntries = true) // allEntries 清空所有缓存,因为操作一个部门,涉及到多个缓存
public void deleteDept(Long id) {
// 校验部门内用户操作
checkCurrentWhenOperate(id);
// 校验是否存在
validateDeptExists(id);
// 校验是否有子部门
@@ -87,6 +98,18 @@ public class DeptServiceImpl implements DeptService {
}
// 删除部门
deptMapper.deleteById(id);
// 删除关联的用户
userService.deleteDeptUsers(id);
}
/**
* 检查是否操作当前部门
*/
private void checkCurrentWhenOperate(Long deptId) {
LoginUser loginUser = SecurityFrameworkUtils.getLoginUser();
if (ObjectUtil.isNotNull(loginUser) && ObjectUtil.equal(deptId, loginUser.getDeptId())) {
throw exception(DEPT_USER_OPER_NOT_ALLOW);
}
}
@VisibleForTesting
@@ -1,6 +1,6 @@
package com.cf.imes.module.system.service.lable;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.CollUtil;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.framework.common.util.json.JsonUtils;
import com.cf.imes.framework.common.util.object.BeanUtils;
@@ -74,7 +74,7 @@ public class LabelServiceImpl implements LabelService {
.select(MachineDO::getId)
.eq(MachineDO::getLabelId, id)
);
if(CollectionUtil.isNotEmpty(machineDOS)) {
if(CollUtil.isNotEmpty(machineDOS)) {
throw exception(MACHINE_USE_LABEL);
}
// 删除标签模板表
@@ -3,6 +3,7 @@ package com.cf.imes.module.system.service.oauth2;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTokenPageReqVO;
import com.cf.imes.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
import com.cf.imes.module.system.dal.dataobject.user.AdminUserDO;
import java.util.List;
@@ -29,6 +30,19 @@ public interface OAuth2TokenService {
*/
OAuth2AccessTokenDO createAccessToken(Long userId, Integer userType, String clientId, List<String> scopes, Boolean large, Integer dbNo, Integer tableNo, String dataCode, Long organId, String nickname);
/**
* 创建访问令牌
* 注意:该流程中,会包含创建刷新令牌的创建
* <p>
* 参考 DefaultTokenServices 的 createAccessToken 方法
*
* @param user 用户实体
* @param userType 用户类型
* @param clientId 客户端编号
* @return 访问令牌的信息
*/
OAuth2AccessTokenDO createAccessToken(AdminUserDO user, Integer userType, String clientId, String dataCode);
/**
* 刷新访问令牌
*
@@ -12,6 +12,7 @@ import com.cf.imes.module.system.controller.admin.oauth2.vo.token.OAuth2AccessTo
import com.cf.imes.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
import com.cf.imes.module.system.dal.dataobject.oauth2.OAuth2ClientDO;
import com.cf.imes.module.system.dal.dataobject.oauth2.OAuth2RefreshTokenDO;
import com.cf.imes.module.system.dal.dataobject.user.AdminUserDO;
import com.cf.imes.module.system.dal.mysql.oauth2.OAuth2AccessTokenMapper;
import com.cf.imes.module.system.dal.mysql.oauth2.OAuth2RefreshTokenMapper;
import com.cf.imes.module.system.dal.redis.oauth2.OAuth2AccessTokenRedisDAO;
@@ -64,6 +65,15 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
return createOAuth2AccessToken(refreshTokenDO, clientDO);
}
@Override
public OAuth2AccessTokenDO createAccessToken(AdminUserDO user, Integer userType, String clientId, String dataCode) {
OAuth2ClientDO clientDO = oauth2ClientService.validOAuthClientFromCache(clientId);
// 填入访问令牌包含的字段
OAuth2AccessTokenDO refreshTokenDO = createOAuth2ReToken(user, userType, clientDO, dataCode);
// 创建访问令牌
return createOAuth2AccessToken(refreshTokenDO, clientDO);
}
@Override
public OAuth2AccessTokenDO refreshAccessToken(String refreshToken, String clientId) {
// 查询访问令牌
@@ -145,7 +155,7 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
.setClientId(clientDO.getClientId()).setScopes(scopes)
.setExpiresTime(LocalDateTime.now().plusSeconds(clientDO.getRefreshTokenValiditySeconds()))
.setLarge(large).setDbNo(dbNo).setTableNo(tableNo).setDataCode(dataCode)
.setOrganId(organId).setNickname(nickname);
.setOrganId(organId).setNickname(nickname).setDeptId(null);
if (organId != null) {
OrganContextHolder.setOrganId(organId);
}
@@ -154,6 +164,24 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
return refreshToken;
}
// 填入访问令牌包含的字段
private OAuth2AccessTokenDO createOAuth2ReToken(AdminUserDO user, Integer userType, OAuth2ClientDO clientDO, String dataCode) {
Long organId = user.getOrganId();
Long userId = user.getId();
OAuth2AccessTokenDO refreshToken = new OAuth2AccessTokenDO().setRefreshToken(generateRefreshToken())
.setUserId(userId).setUserType(userType)
.setClientId(clientDO.getClientId())
.setExpiresTime(LocalDateTime.now().plusSeconds(clientDO.getRefreshTokenValiditySeconds()))
.setDataCode(dataCode)
.setOrganId(organId).setNickname(user.getNickname()).setDeptId(user.getDeptId());
if (organId != null) {
OrganContextHolder.setOrganId(organId);
}
boolean b = securityFrameworkService.hasAnyRoles(userId, "super_admin");
refreshToken.setIsSupAdmin(b);
return refreshToken;
}
// 在Redis中新增Token,除去刷新Token字段
private OAuth2AccessTokenDO createOAuth2AccessToken(OAuth2AccessTokenDO refreshTokenDO, OAuth2ClientDO clientDO) {
OAuth2AccessTokenDO accessTokenDO = new OAuth2AccessTokenDO().setAccessToken(generateAccessToken())
@@ -164,7 +192,7 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
.setLarge(refreshTokenDO.getLarge()).setDbNo(refreshTokenDO.getDbNo()).setTableNo(refreshTokenDO.getTableNo())
.setDataCode(refreshTokenDO.getDataCode()).setOrganId(refreshTokenDO.getOrganId())
.setNickname(refreshTokenDO.getNickname()).setIsSupAdmin(refreshTokenDO.getIsSupAdmin())
;
.setDeptId(refreshTokenDO.getDeptId());
// 记录到 Redis 中
oauth2AccessTokenRedisDAO.set(accessTokenDO);
return accessTokenDO;
@@ -15,6 +15,7 @@ import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cf.imes.framework.organ.config.OrganProperties;
import com.cf.imes.framework.organ.core.context.OrganContextHolder;
import com.cf.imes.framework.organ.core.util.OrganUtils;
import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
import com.cf.imes.module.system.api.organ.dto.OrgStatisticsIsLapseRespDTO;
import com.cf.imes.module.system.api.organ.dto.OrgStatisticsReqDTO;
import com.cf.imes.module.system.constants.permission.InternalRoleConstants;
@@ -46,6 +47,7 @@ import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
@@ -275,11 +277,25 @@ public class OrganServiceImpl implements OrganService {
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteOrgan(Long id) {
// 校验存在
validateUpdateTenant(id);
// 校验机构内用户操作
checkCurrentWhenOperate(id);
// 删除
organMapper.deleteById(id);
// 删除关联的用户
userService.deleteOrgUsers(id);
}
/**
* 检查是否操作当前组织
*/
private void checkCurrentWhenOperate(Long organId) {
if (ObjectUtil.equal(organId, SecurityFrameworkUtils.getUserOrganId())) {
throw exception(ORGAN_USER_OPER_NOT_ALLOW);
}
}
private OrganizationDO validateUpdateTenant(Long id) {
@@ -362,8 +362,12 @@ public class PermissionServiceImpl implements PermissionService {
if (roleService.hasAnySuperAdmin(roleIds)) {
return convertSet(menuService.getMenuList(), MenuDO::getId);
}
if (roleIds.contains(InternalRoleConstants.ORGAN_ADMIN_ROLE_ID)) {
// 组织管理员不限制组织id
List<Long> buildinRoleIdList = new ArrayList<>(){{
add(InternalRoleConstants.ORGAN_ADMIN_ROLE_ID);
add(InternalRoleConstants.ORGAN_STAFF_ROLE_ID);
}};
if (CollUtil.containsAny(roleIds, buildinRoleIdList)) {
// 内置角色不限制组织id
return convertSet(roleMenuMapper.selectListByRoleId(roleIds), RoleMenuDO::getMenuId);
} else {
// 普通成员只能看组织id下的菜单
@@ -105,6 +105,20 @@ public interface AdminUserService {
*/
void deleteUser(Long id);
/**
* 删除组织下的用户
*
* @param organId
*/
void deleteOrgUsers(Long organId);
/**
* 删除部门下的用户
*
* @param deptId
*/
void deleteDeptUsers(Long deptId);
/**
* 通过用户名查询用户
*
@@ -331,6 +331,40 @@ public class AdminUserServiceImpl implements AdminUserService {
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteOrgUsers(Long organId) {
// 查询机构下所有的用户id
List<Long> userIds = userMapper.selectAllOrganUsers(organId);
for (Long userId : userIds) {
// 物理删除用户
int deleteNum = userMapper.physicalDeleteById(userId);
if (deleteNum > 0) {
// 删除用户关联数据
permissionService.processUserDeleted(userId);
// 删除用户岗位
userPostMapper.deleteByUserId(userId);
}
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteDeptUsers(Long deptId) {
// 查询部门下所有的用户id
List<Long> userIds = userMapper.selectAllDeptUsers(deptId);
for (Long userId : userIds) {
// 物理删除用户
int deleteNum = userMapper.physicalDeleteById(userId);
if (deleteNum > 0) {
// 删除用户关联数据
permissionService.processUserDeleted(userId);
// 删除用户岗位
userPostMapper.deleteByUserId(userId);
}
}
}
@Override
public AdminUserDO getUserByUsername(String username, Long organId) {
return userMapper.selectByUsername(username, organId);