mirror of
http://192.168.1.205:9980/cf_devdept2/cf_imes_server.git
synced 2026-08-12 21:02:08 +08:00
1、禅道#795问题修复,支持部门禁用的实时检查;2、新增用户、部门、组织删除和禁用时对对应用户的token移除;
This commit is contained in:
+2
-2
@@ -1,2 +1,2 @@
|
||||
com.cf.imes.framework.datapermission.config.ChenfengDataPermissionAutoConfiguration
|
||||
com.cf.imes.framework.datapermission.config.ChenfengDeptDataPermissionAutoConfiguration
|
||||
#com.cf.imes.framework.datapermission.config.ChenfengDataPermissionAutoConfiguration
|
||||
#com.cf.imes.framework.datapermission.config.ChenfengDeptDataPermissionAutoConfiguration
|
||||
|
||||
+3
-2
@@ -16,6 +16,7 @@ import com.cf.imes.framework.organ.core.service.OrganFrameworkServiceImpl;
|
||||
import com.cf.imes.framework.organ.core.web.OrganContextWebFilter;
|
||||
import com.cf.imes.framework.web.config.WebProperties;
|
||||
import com.cf.imes.framework.web.core.handler.GlobalExceptionHandler;
|
||||
import com.cf.imes.module.system.api.dept.DeptApi;
|
||||
import com.cf.imes.module.system.api.organ.OrganApi;
|
||||
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
|
||||
import com.baomidou.mybatisplus.extension.plugins.inner.TenantLineInnerInterceptor;
|
||||
@@ -42,8 +43,8 @@ import java.util.Objects;
|
||||
public class ChenfengOrganAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public OrganFrameworkService tenantFrameworkService(OrganApi organApi) {
|
||||
return new OrganFrameworkServiceImpl(organApi);
|
||||
public OrganFrameworkService tenantFrameworkService(OrganApi organApi, DeptApi deptApi) {
|
||||
return new OrganFrameworkServiceImpl(organApi, deptApi);
|
||||
}
|
||||
|
||||
// ========== AOP ==========
|
||||
|
||||
+5
@@ -61,8 +61,10 @@ public class OrganSecurityWebFilter extends ApiRequestFilter {
|
||||
throws ServletException, IOException {
|
||||
Long organId = WebFrameworkUtils.getOrganId(request);
|
||||
// 1. 登陆的用户,校验是否有权限访问该组织,避免越权问题。
|
||||
Long deptId = null;
|
||||
LoginUser user = SecurityFrameworkUtils.getLoginUser();
|
||||
if (user != null) {
|
||||
deptId = user.getDeptId();
|
||||
// 如果获取不到组织编号,则尝试使用登陆用户的组织编号
|
||||
if (organId == null) {
|
||||
organId = user.getOrganId();
|
||||
@@ -89,7 +91,10 @@ public class OrganSecurityWebFilter extends ApiRequestFilter {
|
||||
}
|
||||
// 3. 校验组织是合法,例如说被禁用、到期
|
||||
try {
|
||||
// 校验组织
|
||||
organFrameworkService.validOrgan(organId);
|
||||
// 校验部门
|
||||
organFrameworkService.validDept(deptId);
|
||||
} catch (Throwable ex) {
|
||||
CommonResult<?> result = globalExceptionHandler.allExceptionHandler(request, ex);
|
||||
// 组织失效返回401踢出系统
|
||||
|
||||
+6
@@ -23,4 +23,10 @@ public interface OrganFrameworkService {
|
||||
*/
|
||||
void validOrgan(Long id);
|
||||
|
||||
/**
|
||||
* 校验部门是否合法
|
||||
*
|
||||
* @param id
|
||||
*/
|
||||
void validDept(Long id);
|
||||
}
|
||||
|
||||
+7
@@ -1,6 +1,7 @@
|
||||
package com.cf.imes.framework.organ.core.service;
|
||||
|
||||
import com.cf.imes.framework.common.util.cache.CacheUtils;
|
||||
import com.cf.imes.module.system.api.dept.DeptApi;
|
||||
import com.cf.imes.module.system.api.organ.OrganApi;
|
||||
import com.google.common.cache.CacheLoader;
|
||||
import com.google.common.cache.LoadingCache;
|
||||
@@ -20,6 +21,8 @@ public class OrganFrameworkServiceImpl implements OrganFrameworkService {
|
||||
|
||||
private final OrganApi organApi;
|
||||
|
||||
private final DeptApi deptApi;
|
||||
|
||||
/**
|
||||
* 针对 {@link #getOrganIds()} 的缓存
|
||||
*/
|
||||
@@ -46,4 +49,8 @@ public class OrganFrameworkServiceImpl implements OrganFrameworkService {
|
||||
organApi.validOrgan(id).checkError();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validDept(Long id) {
|
||||
deptApi.validateDept(id);
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -9,6 +9,7 @@ import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -37,6 +38,11 @@ public interface DeptApi {
|
||||
@Parameter(name = "ids", description = "部门编号数组", example = "1,2", required = true)
|
||||
CommonResult<Boolean> validateDeptList(@RequestParam("ids") Collection<Long> ids);
|
||||
|
||||
@GetMapping(PREFIX + "/valid/{deptId}")
|
||||
@Operation(summary = "校验部门是否合法")
|
||||
@Parameter(name = "id", description = "部门编号", example = "1024", required = true)
|
||||
CommonResult<Boolean> validateDept(@PathVariable("id") Long deptId);
|
||||
|
||||
/**
|
||||
* 获得指定编号的部门 Map
|
||||
*
|
||||
|
||||
+1
@@ -70,6 +70,7 @@ public class ErrorCodeConstants {
|
||||
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, "不允许操作用户自身部门");
|
||||
public static final ErrorCode DEPT_DISABLE = new ErrorCode(1_002_004_006, "部门({})已被禁用");
|
||||
|
||||
// ========== 岗位模块 1-002-005-000 ==========
|
||||
public static final ErrorCode POST_NOT_FOUND = new ErrorCode(1_002_005_000, "当前岗位不存在");
|
||||
|
||||
+5
@@ -39,4 +39,9 @@ public class DeptApiImpl implements DeptApi {
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CommonResult<Boolean> validateDept(Long deptId) {
|
||||
deptService.validDept(deptId);
|
||||
return success(true);
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -99,4 +99,10 @@ public interface DeptService {
|
||||
*/
|
||||
void validateDeptList(Collection<Long> ids);
|
||||
|
||||
/**
|
||||
* 校验部门是否存在且有效(包括上级)
|
||||
*
|
||||
* @param deptId
|
||||
*/
|
||||
void validDept(Long deptId);
|
||||
}
|
||||
|
||||
+83
-3
@@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.cf.imes.framework.common.enums.CommonStatusEnum;
|
||||
import com.cf.imes.framework.common.exception.util.ServiceExceptionUtil;
|
||||
import com.cf.imes.framework.common.util.json.JsonUtils;
|
||||
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;
|
||||
@@ -11,6 +12,7 @@ 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.dataobject.oauth2.OAuth2AccessTokenDO;
|
||||
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;
|
||||
@@ -20,6 +22,9 @@ 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.data.redis.core.Cursor;
|
||||
import org.springframework.data.redis.core.ScanOptions;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
@@ -28,6 +33,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.dal.redis.RedisKeyConstants.OAUTH2_ACCESS_TOKEN;
|
||||
import static com.cf.imes.module.system.enums.ErrorCodeConstants.DEPT_USER_OPER_NOT_ALLOW;
|
||||
|
||||
/**
|
||||
@@ -47,6 +53,9 @@ public class DeptServiceImpl implements DeptService {
|
||||
@Lazy // 延迟,避免循环依赖报错
|
||||
private AdminUserService userService;
|
||||
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
@Override
|
||||
@CacheEvict(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST,
|
||||
allEntries = true) // allEntries 清空所有缓存,因为操作一个部门,涉及到多个缓存
|
||||
@@ -69,19 +78,26 @@ public class DeptServiceImpl implements DeptService {
|
||||
@CacheEvict(cacheNames = RedisKeyConstants.DEPT_CHILDREN_ID_LIST,
|
||||
allEntries = true) // allEntries 清空所有缓存,因为操作一个部门,涉及到多个缓存
|
||||
public void updateDept(DeptSaveReqVO updateReqVO) {
|
||||
Long deptId = updateReqVO.getId();
|
||||
if (updateReqVO.getParentId() == null) {
|
||||
updateReqVO.setParentId(DeptDO.PARENT_ID_ROOT);
|
||||
}
|
||||
// 校验自己存在
|
||||
validateDeptExists(updateReqVO.getId());
|
||||
validateDeptExists(deptId);
|
||||
// 校验父部门的有效性
|
||||
validateParentDept(updateReqVO.getId(), updateReqVO.getParentId());
|
||||
validateParentDept(deptId, updateReqVO.getParentId());
|
||||
// 校验部门名的唯一性
|
||||
validateDeptNameUnique(updateReqVO.getId(), updateReqVO.getParentId(), updateReqVO.getName(), updateReqVO.getOrganId());
|
||||
validateDeptNameUnique(deptId, updateReqVO.getParentId(), updateReqVO.getName(), updateReqVO.getOrganId());
|
||||
// 校验部门内用户操作
|
||||
checkCurrentWhenOperate(deptId);
|
||||
|
||||
// 更新部门
|
||||
DeptDO updateObj = BeanUtils.toBean(updateReqVO, DeptDO.class);
|
||||
deptMapper.updateById(updateObj);
|
||||
if (CommonStatusEnum.DISABLE.getStatus().equals(updateReqVO.getStatus())) {
|
||||
// 移除部门下用户的token
|
||||
scanAndCompareDeptAndDelToken(String.format(OAUTH2_ACCESS_TOKEN, "*"), deptId);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -100,6 +116,35 @@ public class DeptServiceImpl implements DeptService {
|
||||
deptMapper.deleteById(id);
|
||||
// 删除关联的用户
|
||||
userService.deleteDeptUsers(id);
|
||||
// 移除部门下用户的token
|
||||
scanAndCompareDeptAndDelToken(String.format(OAUTH2_ACCESS_TOKEN, "*"), id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 轮训redis token,移除对应部门下的用户的token
|
||||
*
|
||||
* @param keyPattern
|
||||
* @param deptId
|
||||
*/
|
||||
private void scanAndCompareDeptAndDelToken(String keyPattern, Long deptId) {
|
||||
// 根据keyPattern scan匹配的redis key
|
||||
List<String> matchKeys = new ArrayList<>();
|
||||
Cursor<String> cursor = stringRedisTemplate.scan(ScanOptions.scanOptions().match(keyPattern).count(200).build());
|
||||
while (cursor.hasNext()) {
|
||||
matchKeys.add(cursor.next());
|
||||
}
|
||||
cursor.close();
|
||||
if (CollUtil.isNotEmpty(matchKeys)) {
|
||||
for (String key : matchKeys) {
|
||||
// 获取key下的用户信息
|
||||
OAuth2AccessTokenDO oAuth2AccessTokenDO = JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(key), OAuth2AccessTokenDO.class);
|
||||
if (ObjectUtil.equal(deptId, oAuth2AccessTokenDO.getDeptId())) {
|
||||
// 用户id匹配上了删除redis中的token缓存
|
||||
stringRedisTemplate.delete(key);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -239,4 +284,39 @@ public class DeptServiceImpl implements DeptService {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validDept(Long deptId) {
|
||||
DeptDO deptDO = deptMapper.selectById(deptId);
|
||||
if (deptDO == null) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.DEPT_NOT_FOUND);
|
||||
}
|
||||
if (!CommonStatusEnum.ENABLE.getStatus().equals(deptDO.getStatus())) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.DEPT_DISABLE, deptDO.getName());
|
||||
}
|
||||
// 递归校验上级部门
|
||||
validParentDept(deptDO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归校验上级部门
|
||||
*
|
||||
* @param deptDO
|
||||
*/
|
||||
private void validParentDept(DeptDO deptDO) {
|
||||
if (ObjectUtil.isNotNull(deptDO) && ObjectUtil.isNotNull(deptDO.getParentId())) {
|
||||
Long parentId = deptDO.getParentId();
|
||||
DeptDO parentDept = deptMapper.selectById(parentId);
|
||||
if (ObjectUtil.equal(parentId, 0L)) {
|
||||
// 上级部门id是0代表是机构下最顶级的部门
|
||||
return;
|
||||
}
|
||||
if (parentDept == null) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.DEPT_PARENT_NOT_EXITS);
|
||||
} else if (!CommonStatusEnum.ENABLE.getStatus().equals(parentDept.getStatus())) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.DEPT_DISABLE, parentDept.getName());
|
||||
} else {
|
||||
validParentDept(parentDept);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+46
-3
@@ -9,6 +9,7 @@ import com.cf.imes.framework.common.enums.CommonStatusEnum;
|
||||
import com.cf.imes.framework.common.pojo.PageResult;
|
||||
import com.cf.imes.framework.common.util.collection.CollectionUtils;
|
||||
import com.cf.imes.framework.common.util.date.DateUtils;
|
||||
import com.cf.imes.framework.common.util.json.JsonUtils;
|
||||
import com.cf.imes.framework.common.util.object.BeanUtils;
|
||||
import com.cf.imes.framework.common.util.pinyin.PinYinUtils;
|
||||
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
@@ -27,6 +28,7 @@ import com.cf.imes.module.system.controller.admin.organ.vo.organ.OrganSaveReqVO;
|
||||
import com.cf.imes.module.system.controller.admin.user.vo.user.UserSaveReqVO;
|
||||
import com.cf.imes.module.system.convert.organ.OrganConvert;
|
||||
import com.cf.imes.module.system.dal.dataobject.machine.MachineLimitDO;
|
||||
import com.cf.imes.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
|
||||
import com.cf.imes.module.system.dal.dataobject.permission.MenuDO;
|
||||
import com.cf.imes.module.system.dal.dataobject.permission.RoleDO;
|
||||
import com.cf.imes.module.system.dal.dataobject.organ.OrganizationDO;
|
||||
@@ -46,6 +48,9 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.data.redis.core.Cursor;
|
||||
import org.springframework.data.redis.core.ScanOptions;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
@@ -55,6 +60,7 @@ import java.time.LocalDateTime;
|
||||
import java.util.*;
|
||||
|
||||
import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static com.cf.imes.module.system.dal.redis.RedisKeyConstants.OAUTH2_ACCESS_TOKEN;
|
||||
import static com.cf.imes.module.system.enums.ErrorCodeConstants.*;
|
||||
import static java.util.Collections.singleton;
|
||||
|
||||
@@ -93,6 +99,9 @@ public class OrganServiceImpl implements OrganService {
|
||||
@Resource
|
||||
private MachineLimitMapper machineLimitMapper;
|
||||
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
|
||||
@Override
|
||||
public List<Long> getOrganIdList() {
|
||||
@@ -205,12 +214,13 @@ public class OrganServiceImpl implements OrganService {
|
||||
@Override
|
||||
@DSTransactional // 多数据源,使用 @DSTransactional 保证本地事务,以及数据源的切换
|
||||
public void updateOrgan(OrganSaveReqVO updateReqVO) {
|
||||
Long organId = updateReqVO.getId();
|
||||
// 校验存在
|
||||
OrganizationDO tenant = validateUpdateTenant(updateReqVO.getId());
|
||||
OrganizationDO tenant = validateUpdateTenant(organId);
|
||||
// 校验组织名称是否重复
|
||||
validTenantNameDuplicate(updateReqVO.getName(), updateReqVO.getId());
|
||||
validTenantNameDuplicate(updateReqVO.getName(), organId);
|
||||
// 校验组织域名是否重复
|
||||
validTenantWebsiteDuplicate(updateReqVO.getWebsite(), updateReqVO.getId());
|
||||
validTenantWebsiteDuplicate(updateReqVO.getWebsite(), organId);
|
||||
// 校验套餐被禁用
|
||||
TenantPackageDO tenantPackage = tenantPackageService.validTenantPackage(updateReqVO.getPackageId());
|
||||
if(!Objects.equals(tenant.getName(), updateReqVO.getName())) {
|
||||
@@ -228,6 +238,10 @@ public class OrganServiceImpl implements OrganService {
|
||||
if (ObjectUtil.notEqual(tenant.getPackageId(), updateReqVO.getPackageId())) {
|
||||
permissionService.flushCacheWhenTenantPackageChange(List.of(tenant.getId()));
|
||||
}
|
||||
if (CommonStatusEnum.DISABLE.getStatus().equals(updateReqVO.getStatus())) {
|
||||
// 移除机构下用户的token
|
||||
scanAndCompareDeptAndDelToken(String.format(OAUTH2_ACCESS_TOKEN, "*"), organId);
|
||||
}
|
||||
}
|
||||
|
||||
private void validTenantNameDuplicate(String name, Long id) {
|
||||
@@ -297,6 +311,35 @@ public class OrganServiceImpl implements OrganService {
|
||||
organMapper.deleteById(id);
|
||||
// 删除关联的用户
|
||||
userService.deleteOrgUsers(id);
|
||||
// 移除机构下用户的token
|
||||
scanAndCompareDeptAndDelToken(String.format(OAUTH2_ACCESS_TOKEN, "*"), id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 轮训redis token,移除对应机构下的用户的token
|
||||
*
|
||||
* @param keyPattern
|
||||
* @param organId
|
||||
*/
|
||||
private void scanAndCompareDeptAndDelToken(String keyPattern, Long organId) {
|
||||
// 根据keyPattern scan匹配的redis key
|
||||
List<String> matchKeys = new ArrayList<>();
|
||||
Cursor<String> cursor = stringRedisTemplate.scan(ScanOptions.scanOptions().match(keyPattern).count(200).build());
|
||||
while (cursor.hasNext()) {
|
||||
matchKeys.add(cursor.next());
|
||||
}
|
||||
cursor.close();
|
||||
if (CollUtil.isNotEmpty(matchKeys)) {
|
||||
for (String key : matchKeys) {
|
||||
// 获取key下的用户信息
|
||||
OAuth2AccessTokenDO oAuth2AccessTokenDO = JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(key), OAuth2AccessTokenDO.class);
|
||||
if (ObjectUtil.equal(organId, oAuth2AccessTokenDO.getOrganId())) {
|
||||
// 用户id匹配上了删除redis中的token缓存
|
||||
stringRedisTemplate.delete(key);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+76
-32
@@ -12,11 +12,11 @@ import com.cf.imes.framework.common.exception.ServiceException;
|
||||
import com.cf.imes.framework.common.exception.util.ServiceExceptionUtil;
|
||||
import com.cf.imes.framework.common.pojo.PageResult;
|
||||
import com.cf.imes.framework.common.util.collection.CollectionUtils;
|
||||
import com.cf.imes.framework.common.util.json.JsonUtils;
|
||||
import com.cf.imes.framework.common.util.monitor.TracerUtils;
|
||||
import com.cf.imes.framework.common.util.object.BeanUtils;
|
||||
import com.cf.imes.framework.common.util.pinyin.PinYinUtils;
|
||||
import com.cf.imes.framework.common.util.servlet.ServletUtils;
|
||||
import com.cf.imes.framework.datapermission.core.util.DataPermissionUtils;
|
||||
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import com.cf.imes.framework.mybatis.core.query.MPJLambdaWrapperX;
|
||||
import com.cf.imes.framework.organ.core.aop.OrganIgnore;
|
||||
@@ -37,6 +37,7 @@ import com.cf.imes.module.system.controller.admin.user.vo.user.UserResetPassword
|
||||
import com.cf.imes.module.system.controller.admin.user.vo.user.UserSaveReqVO;
|
||||
import com.cf.imes.module.system.dal.dataobject.dept.DeptDO;
|
||||
import com.cf.imes.module.system.dal.dataobject.dept.UserPostDO;
|
||||
import com.cf.imes.module.system.dal.dataobject.oauth2.OAuth2AccessTokenDO;
|
||||
import com.cf.imes.module.system.dal.dataobject.permission.UserRoleDO;
|
||||
import com.cf.imes.module.system.dal.dataobject.user.AdminUserDO;
|
||||
import com.cf.imes.module.system.dal.mysql.dept.UserPostMapper;
|
||||
@@ -56,6 +57,9 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.data.redis.core.Cursor;
|
||||
import org.springframework.data.redis.core.ScanOptions;
|
||||
import org.springframework.data.redis.core.StringRedisTemplate;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -71,6 +75,7 @@ import java.util.regex.Pattern;
|
||||
import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception;
|
||||
import static com.cf.imes.framework.common.util.collection.CollectionUtils.convertList;
|
||||
import static com.cf.imes.framework.common.util.collection.CollectionUtils.convertSet;
|
||||
import static com.cf.imes.module.system.dal.redis.RedisKeyConstants.OAUTH2_ACCESS_TOKEN;
|
||||
import static com.cf.imes.module.system.enums.ErrorCodeConstants.USER_ME_ERROR;
|
||||
import static com.cf.imes.module.system.enums.ErrorCodeConstants.USER_OPERATE_SELF_STATUS_ERROR;
|
||||
|
||||
@@ -113,6 +118,8 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
@Resource
|
||||
private LoginLogService loginLogService;
|
||||
|
||||
@Resource
|
||||
private StringRedisTemplate stringRedisTemplate;
|
||||
|
||||
// 定义密码校验的正则表达式
|
||||
private static final String LENGTH_PATTERN = ".{8,}";
|
||||
@@ -125,7 +132,7 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long createUser(UserSaveReqVO createReqVO) {
|
||||
Long organId = createReqVO.getOrganId() == null ? OrganContextHolder.getOrganId(): createReqVO.getOrganId();
|
||||
Long organId = createReqVO.getOrganId() == null ? OrganContextHolder.getOrganId() : createReqVO.getOrganId();
|
||||
// 校验账户配合
|
||||
organService.handleOrganInfo(organ -> {
|
||||
long count = userMapper.selectCount(new LambdaQueryWrapperX<AdminUserDO>().eq(AdminUserDO::getOrganId, organId));
|
||||
@@ -160,17 +167,18 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateUser(UserSaveReqVO updateReqVO) {
|
||||
Long organId = updateReqVO.getOrganId() == null ? OrganContextHolder.getOrganId(): updateReqVO.getOrganId();
|
||||
Long organId = updateReqVO.getOrganId() == null ? OrganContextHolder.getOrganId() : updateReqVO.getOrganId();
|
||||
String mobile = updateReqVO.getMobile();
|
||||
Long userId = updateReqVO.getId();
|
||||
// 不允许关闭自身状态
|
||||
checkCurrentWhenOperateStatus(updateReqVO.getId(), updateReqVO.getStatus());
|
||||
checkCurrentWhenOperateStatus(userId, updateReqVO.getStatus());
|
||||
// 校验正确性
|
||||
validateUserForCreateOrUpdate(updateReqVO.getId(), mobile,
|
||||
AdminUserDO currUserDO = validateUserForCreateOrUpdate(userId, mobile,
|
||||
updateReqVO.getEmail(), updateReqVO.getDeptId(), updateReqVO.getPostIds(), null, organId);
|
||||
// 更新用户
|
||||
AdminUserDO updateObj = BeanUtils.toBean(updateReqVO, AdminUserDO.class);
|
||||
|
||||
if(!Objects.isNull(updateReqVO.getNickname())) {
|
||||
if (!Objects.isNull(updateReqVO.getNickname())) {
|
||||
|
||||
String pinyinFull = PinYinUtils.convertToPinyin(updateReqVO.getNickname());
|
||||
if (StringUtils.isNotBlank(pinyinFull)) {
|
||||
@@ -192,6 +200,37 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
userMapper.updateById(updateObj);
|
||||
// 更新岗位
|
||||
updateUserPost(updateReqVO, updateObj);
|
||||
// 如果改变了部门或修改状态为禁用移除用户token
|
||||
if (ObjectUtil.notEqual(currUserDO.getDeptId(), updateReqVO.getDeptId()) || CommonStatusEnum.DISABLE.getStatus().equals(updateReqVO.getStatus())) {
|
||||
scanAndCompareUserAndDelToken(String.format(OAUTH2_ACCESS_TOKEN, "*"), userId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 轮训redis token,移除对应用户的token
|
||||
*
|
||||
* @param keyPattern
|
||||
* @param userId
|
||||
*/
|
||||
private void scanAndCompareUserAndDelToken(String keyPattern, Long userId) {
|
||||
// 根据keyPattern scan匹配的redis key
|
||||
List<String> matchKeys = new ArrayList<>();
|
||||
Cursor<String> cursor = stringRedisTemplate.scan(ScanOptions.scanOptions().match(keyPattern).count(200).build());
|
||||
while (cursor.hasNext()) {
|
||||
matchKeys.add(cursor.next());
|
||||
}
|
||||
cursor.close();
|
||||
if (CollUtil.isNotEmpty(matchKeys)) {
|
||||
for (String key : matchKeys) {
|
||||
// 获取key下的用户信息
|
||||
OAuth2AccessTokenDO oAuth2AccessTokenDO = JsonUtils.parseObject(stringRedisTemplate.opsForValue().get(key), OAuth2AccessTokenDO.class);
|
||||
if (ObjectUtil.equal(userId, oAuth2AccessTokenDO.getUserId())) {
|
||||
// 用户id匹配上了删除redis中的token缓存
|
||||
stringRedisTemplate.delete(key);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateUserPost(UserSaveReqVO reqVO, AdminUserDO updateObj) {
|
||||
@@ -313,6 +352,10 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
updateObj.setId(id);
|
||||
updateObj.setStatus(status);
|
||||
userMapper.updateById(updateObj);
|
||||
if (CommonStatusEnum.DISABLE.getStatus().equals(status)) {
|
||||
// 移除用户token
|
||||
scanAndCompareUserAndDelToken(String.format(OAUTH2_ACCESS_TOKEN, "*"), id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -329,6 +372,8 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
permissionService.processUserDeleted(id);
|
||||
// 删除用户岗位
|
||||
userPostMapper.deleteByUserId(id);
|
||||
// 移除用户token
|
||||
scanAndCompareUserAndDelToken(String.format(OAUTH2_ACCESS_TOKEN, "*"), id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -479,27 +524,25 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
return deptIds;
|
||||
}
|
||||
|
||||
private void validateUserForCreateOrUpdate(Long id, String username, String email,
|
||||
Long deptId, Set<Long> postIds,String password ,Long organId) {
|
||||
// 关闭数据权限,避免因为没有数据权限,查询不到数据,进而导致唯一校验不正确
|
||||
DataPermissionUtils.executeIgnore(() -> {
|
||||
// 校验用户的密码是否符合规则
|
||||
if(password != null) {
|
||||
validatePassword(password);
|
||||
}
|
||||
// 校验用户存在
|
||||
validateUserExists(id);
|
||||
// 校验用户名唯一
|
||||
validateUsernameUnique(id, username, organId);
|
||||
// 校验部门处于开启状态
|
||||
deptService.validateDeptList(CollectionUtils.singleton(deptId));
|
||||
// 校验岗位处于开启状态
|
||||
postService.validatePostList(postIds);
|
||||
});
|
||||
private AdminUserDO validateUserForCreateOrUpdate(Long id, String username, String email,
|
||||
Long deptId, Set<Long> postIds, String password, Long organId) {
|
||||
// 校验用户的密码是否符合规则
|
||||
if (password != null) {
|
||||
validatePassword(password);
|
||||
}
|
||||
// 校验用户存在
|
||||
AdminUserDO adminUserDO = validateUserExists(id);
|
||||
// 校验用户名唯一
|
||||
validateUsernameUnique(id, username, organId);
|
||||
// 校验部门处于开启状态
|
||||
deptService.validDept(deptId);
|
||||
// 校验岗位处于开启状态
|
||||
postService.validatePostList(postIds);
|
||||
return adminUserDO;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void validatePassword(String password){
|
||||
void validatePassword(String password) {
|
||||
|
||||
// 检查密码长度
|
||||
if (!Pattern.matches(LENGTH_PATTERN, password)) {
|
||||
@@ -526,17 +569,18 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.THE_PASSWORD_LENGTH_MUST_BE_AT_LEAST_8_CHARACTERS);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void validateUserExists(Long id) {
|
||||
AdminUserDO validateUserExists(Long id) {
|
||||
if (id == null) {
|
||||
return;
|
||||
return null;
|
||||
}
|
||||
AdminUserDO user = userMapper.selectById(id);
|
||||
if (user == null) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.USER_NOT_EXISTS);
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@@ -631,7 +675,7 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
// 校验,判断是否有不符合的原因
|
||||
try {
|
||||
validateUserForCreateOrUpdate(null, null, importUser.getEmail(),
|
||||
importUser.getDeptId(), null,null, organId);
|
||||
importUser.getDeptId(), null, null, organId);
|
||||
} catch (ServiceException ex) {
|
||||
respVO.getFailureUsernames().put(importUser.getUsername(), ex.getMessage());
|
||||
return;
|
||||
@@ -673,7 +717,7 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
public List<AdminUserDO> getUserListByTerms(Integer status, String name) {
|
||||
String namePyFirstChar = "";
|
||||
String namePyAll = "";
|
||||
if(StringUtils.isNotBlank(name)) {
|
||||
if (StringUtils.isNotBlank(name)) {
|
||||
namePyFirstChar = PinYinUtils.convertToPinyin(name);
|
||||
namePyAll = PinYinUtils.convertToPinyin(name).replace(" ", "");
|
||||
}
|
||||
@@ -683,11 +727,11 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
@Override
|
||||
@OrganIgnore
|
||||
public List<OrganAdminUserRespDTO> getOrganAdminByOrganIds(Collection<Long> organIds) {
|
||||
if(CollUtil.isEmpty(organIds)) {
|
||||
if (CollUtil.isEmpty(organIds)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
MPJLambdaWrapperX<AdminUserDO> wrapperX = new MPJLambdaWrapperX<>();
|
||||
wrapperX.leftJoin(UserRoleDO.class, UserRoleDO::getUserId, AdminUserDO::getId)
|
||||
wrapperX.leftJoin(UserRoleDO.class, UserRoleDO::getUserId, AdminUserDO::getId)
|
||||
.eq(UserRoleDO::getRoleId, InternalRoleConstants.ORGAN_ADMIN_ROLE_ID)
|
||||
;
|
||||
List<OrganAdminUserRespDTO> organAdminUserRespDTOS = userMapper.selectJoinList(OrganAdminUserRespDTO.class, wrapperX);
|
||||
@@ -777,7 +821,7 @@ public class AdminUserServiceImpl implements AdminUserService {
|
||||
return map;
|
||||
}
|
||||
|
||||
// 获得此月第一天日期
|
||||
// 获得此月第一天日期
|
||||
public LocalDateTime getFirstDayOfMonth() {
|
||||
// 获取当前日期
|
||||
LocalDate today = LocalDate.now();
|
||||
|
||||
Reference in New Issue
Block a user