feat(tenant): 新增租户信息自动校验与更新功能

- 在SysTenantService中新增getOrUpdateTenant方法实现租户状态自动校验
- 用户登录后自动检查并更新过期租户信息至有效租户
- 重构租户删除逻辑至removeTenant方法并统一缓存清理
- 将用户租户更新接口迁移至SysTenantController
- 优化用户信息查询时自动触发租户校验逻辑
This commit is contained in:
PIG AI committed 2025-07-05 09:06:08 +08:00
1 parent c0e9ed69be
commit bcfeec31bc
6 files changed
+148 -52

No files matched your search

@@ -36,6 +36,7 @@ import com.pig4cloud.pigx.common.excel.annotation.ResponseExcel;
import com.pig4cloud.pigx.common.log.annotation.SysLog;
import com.pig4cloud.pigx.common.security.annotation.HasPermission;
import com.pig4cloud.pigx.common.security.annotation.Inner;
import com.pig4cloud.pigx.common.security.util.SecurityUtils;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
@@ -138,9 +139,8 @@ public class SysTenantController {
@SysLog("删除租户")
@DeleteMapping
@HasPermission("sys_systenant_del")
@CacheEvict(value = CacheConstants.TENANT_DETAILS, allEntries = true)
public R removeById(@RequestBody Long[] ids) {
return R.ok(sysTenantService.removeBatchByIds(CollUtil.toList(ids)));
return R.ok(sysTenantService.removeTenant(ids));
}
/**
@@ -262,4 +262,18 @@ public class SysTenantController {
return R.ok(sysTenantService.listTenantOrg(userDTO));
}
/**
* 更新用户租户信息
*
* @param userDto 用户数据传输对象,包含需要更新的用户信息
* @return 操作结果
*/
@PutMapping("/personal/update")
public R updateUserTenant(@RequestBody UserDTO userDto) {
String username = SecurityUtils.getUser().getUsername();
userDto.setUsername(username);
userDto.setUserId(SecurityUtils.getUser().getId());
return sysTenantService.updateUserTenant(userDto);
}
}
@@ -196,20 +196,6 @@ public class SysUserController {
return userService.changePassword(userDto);
}
/**
* 更新用户租户信息
*
* @param userDto 用户数据传输对象,包含需要更新的用户信息
* @return 操作结果
*/
@PutMapping("/personal/tenant")
public R updateUserTenant(@RequestBody UserDTO userDto) {
String username = SecurityUtils.getUser().getUsername();
userDto.setUsername(username);
userDto.setUserId(SecurityUtils.getUser().getId());
return userService.updateUserTenant(userDto);
}
/**
* @param username 用户名称
@@ -23,6 +23,7 @@ import com.pig4cloud.pigx.admin.api.dto.SysTenantUserDTO;
import com.pig4cloud.pigx.admin.api.dto.UserDTO;
import com.pig4cloud.pigx.admin.api.entity.SysTenant;
import com.pig4cloud.pigx.admin.api.entity.SysUser;
import com.pig4cloud.pigx.common.core.util.R;
import java.util.List;
import java.util.Map;
@@ -105,4 +106,25 @@ public interface SysTenantService extends IService<SysTenant> {
* @return 租户角色列表
*/
Map<String, Object> listTenantOrg(UserDTO userDTO);
/**
* 移除租户
*
* @param ids 租户ID列表
* @return 是否移除成功
*/
Boolean removeTenant(Long[] ids);
/**
* 更新用户租户信息
*
* @param userDto 用户数据传输对象
* @return 更新结果
*/
R updateUserTenant(UserDTO userDto);
/**
* 检查或更新租户信息
*/
Long getOrUpdateTenant();
}
@@ -196,11 +196,4 @@ public interface SysUserService extends IService<SysUser> {
*/
R<Boolean> forgetUserPassword(RegisterUserDTO userDto, String code);
/**
* 更新用户租户信息
*
* @param userDto 用户数据传输对象
* @return 更新结果
*/
R updateUserTenant(UserDTO userDto);
}
@@ -33,20 +33,21 @@ import com.pig4cloud.pigx.admin.mapper.*;
import com.pig4cloud.pigx.admin.service.*;
import com.pig4cloud.pigx.common.core.constant.CacheConstants;
import com.pig4cloud.pigx.common.core.constant.CommonConstants;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.core.util.SpringContextHolder;
import com.pig4cloud.pigx.common.data.cache.RedisUtils;
import com.pig4cloud.pigx.common.data.datascope.DataScopeTypeEnum;
import com.pig4cloud.pigx.common.data.resolver.ParamResolver;
import com.pig4cloud.pigx.common.data.tenant.TenantBroker;
import com.pig4cloud.pigx.common.security.service.PigxUser;
import com.pig4cloud.pigx.common.security.util.SecurityUtils;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.SneakyThrows;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -66,20 +67,14 @@ import java.util.*;
@AllArgsConstructor
public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant> implements SysTenantService {
private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();
private final SysOauthClientDetailsService clientServices;
private final SysUserRoleService userRoleService;
private final SysRoleMenuMapper roleMenuMapper;
private final SysDictItemService dictItemService;
private final SysPublicParamService paramService;
private final SysUserService userService;
private final SysRoleService roleService;
private final SysMenuService menuService;
@@ -96,6 +91,7 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
private final SysRoleMapper sysRoleMapper;
private final SysDeptMapper sysDeptMapper;
private final SysPostMapper sysPostMapper;
private final CacheManager cacheManager;
/**
* 获取正常状态租户
@@ -467,6 +463,34 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
});
}
/**
* 移除租户
*
* @param ids 租户ID列表
* @return 是否移除成功
*/
@Override
@CacheEvict(value = CacheConstants.TENANT_DETAILS, allEntries = true)
public Boolean removeTenant(Long[] ids) {
baseMapper.deleteByIds(CollUtil.toList(ids));
sysTenantUserMapper.delete(Wrappers.<SysTenantUser>lambdaQuery().in(SysTenantUser::getTenantId, CollUtil.toList(ids)));
return Boolean.TRUE;
}
/**
* 更新用户租户信息
*
* @param userDto 用户数据传输对象
* @return 更新结果
*/
@Override
@CacheEvict(value = CacheConstants.USER_DETAILS, key = "#userDto.username")
public R updateUserTenant(UserDTO userDto) {
return R.ok(TenantBroker.noneAs(() -> sysUserMapper.update(Wrappers.<SysUser>lambdaUpdate()
.set(SysUser::getTenantId, userDto.getTenantId())
.eq(SysUser::getUserId, userDto.getUserId()))));
}
/**
* 保存新的租户菜单,维护成新的菜单
*
@@ -486,6 +510,41 @@ public class SysTenantServiceImpl extends ServiceImpl<SysTenantMapper, SysTenant
});
}
/**
* 获取或更新当前用户的租户信息
*
* @return 更新后的租户ID,如果无需更新则返回null
*/
@Override
public Long getOrUpdateTenant() {
PigxUser loginUser = SecurityUtils.getUser();
boolean match = this.getNormalTenant()
.stream()
.filter(tenant -> tenant.getStartTime().isBefore(LocalDateTime.now()))
.filter(tenant -> tenant.getEndTime().isAfter(LocalDateTime.now()))
.anyMatch(tenant -> tenant.getId().equals(loginUser.getTenantId()));
if (!match) {
SysTenantUser tenantUser = sysTenantUserMapper.selectOne(Wrappers.<SysTenantUser>lambdaQuery()
.eq(SysTenantUser::getUserId, SecurityUtils.getUser().getId())
.ne(SysTenantUser::getTenantId, loginUser.getTenantId()), false);
// 如果当前用户没有租户信息,则不进行任何操作
if (Objects.isNull(tenantUser)) {
return null;
}
// 切换至状态正常的租户
UserDTO userDTO = new UserDTO();
userDTO.setUserId(loginUser.getId());
userDTO.setTenantId(tenantUser.getTenantId());
userDTO.setUsername(loginUser.getUsername());
updateUserTenant(userDTO);
cacheManager.getCache(CacheConstants.USER_DETAILS).evict(loginUser.getUsername());
return tenantUser.getTenantId();
}
return null;
}
}
/**
@@ -46,7 +46,6 @@ import com.pig4cloud.pigx.common.core.util.MsgUtils;
import com.pig4cloud.pigx.common.core.util.R;
import com.pig4cloud.pigx.common.data.datascope.DataScope;
import com.pig4cloud.pigx.common.data.resolver.ParamResolver;
import com.pig4cloud.pigx.common.data.tenant.TenantBroker;
import com.pig4cloud.pigx.common.excel.vo.ErrorMessage;
import com.pig4cloud.pigx.common.security.service.PigxUser;
import com.pig4cloud.pigx.common.security.util.SecurityUtils;
@@ -86,6 +85,8 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
private final SysDeptService sysDeptService;
private final SysTenantService sysTenantService;
private final SysUserRoleMapper sysUserRoleMapper;
private final SysUserPostMapper sysUserPostMapper;
@@ -95,6 +96,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
private final SysTenantUserMapper sysTenantUserMapper;
private final CacheManager cacheManager;
private final SysDeptMapper sysDeptMapper;
private final StringRedisTemplate redisTemplate;
@@ -184,10 +186,19 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
.stream()
.map(SysRole::getRoleId)
.flatMap(roleId -> sysMenuService.findMenuByRoleId(roleId).stream())
.filter(menu -> StrUtil.isNotEmpty(menu.getPermission()))
.map(SysMenu::getPermission)
.filter(StrUtil::isNotEmpty)
.toList();
userInfo.setPermissions(permissions);
// 如果是登录成功以后查询租户信息并进行校验
if (Objects.nonNull(SecurityUtils.getUser())) {
Long updateTenantId = sysTenantService.getOrUpdateTenant();
if (Objects.nonNull(updateTenantId)) {
userInfo.setTenantId(updateTenantId);
}
}
return R.ok(userInfo);
}
@@ -342,8 +353,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
// 根据数据权限查询全部的用户信息
userDTO.setTenantId(SecurityUtils.getUser().getTenantId());
List<UserVO> voList = baseMapper.selectVoListByScope(userDTO, ids, DataScope.of());
// 转换成execl 对象输出
List<UserExcelVO> userExcelVOList = voList.stream().map(userVO -> {
return voList.stream().map(userVO -> {
UserExcelVO excelVO = new UserExcelVO();
BeanUtils.copyProperties(userVO, excelVO);
// 转换角色名称
@@ -365,7 +375,6 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
excelVO.setDeptNameList(deptNameList);
return excelVO;
}).toList();
return userExcelVOList;
}
/**
@@ -508,7 +517,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
* 锁定用户
*
* @param username 用户名
* @return
* @return 操作结果,包含是否成功
*/
@Override
@CacheEvict(value = CacheConstants.USER_DETAILS, key = "#username")
@@ -522,6 +531,13 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
return R.ok();
}
/**
* 修改用户密码
*
* @param userDto 用户数据传输对象,包含原密码和新密码
* @return 操作结果
* @CacheEvict 清除用户详情缓存
*/
@Override
@CacheEvict(value = CacheConstants.USER_DETAILS, key = "#userDto.username")
public R changePassword(UserDTO userDto) {
@@ -549,19 +565,11 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
/**
* 更新用户租户信息
* 解绑用户第三方登录账号
*
* @param userDto 用户数据传输对象
* @return 更新结果
* @param type 登录类型,参见LoginTypeEnum枚举
* @return 操作结果,成功返回R.ok(),失败返回R.failed()
*/
@Override
@CacheEvict(value = CacheConstants.USER_DETAILS, key = "#userDto.username")
public R updateUserTenant(UserDTO userDto) {
return R.ok(TenantBroker.noneAs(() -> this.update(Wrappers.<SysUser>lambdaUpdate()
.set(SysUser::getTenantId, userDto.getTenantId())
.eq(SysUser::getUserId, userDto.getUserId()))));
}
@Override
public R unbinding(String type) {
PigxUser user = SecurityUtils.getUser();
@@ -596,6 +604,13 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
return R.ok();
}
/**
* 检查用户密码是否正确
*
* @param username 用户名
* @param password 待验证的密码
* @return 验证结果,成功返回R.ok(),失败返回R.failed()
*/
@Override
public R checkPassword(String username, String password) {
SysUser condition = new SysUser();
@@ -613,8 +628,8 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
/**
* 重置用户密码
*
* @param userDto 用户信息
* @return
* @param userDto 用户信息DTO,包含用户名、原密码和新密码等信息
* @return 返回操作结果,成功返回true,失败返回错误信息
*/
@Override
@CacheEvict(value = CacheConstants.USER_DETAILS, key = "#userDto.username")
@@ -640,14 +655,21 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
return R.ok();
}
/**
* 忘记用户密码
*
* @param userDto 用户信息DTO
* @param code 验证码
* @return 操作结果,成功返回true
*/
@Override
public R<Boolean> forgetUserPassword(RegisterUserDTO userDto, String code) {
if (StrUtil.isBlank(userDto.getPhone())){
if (StrUtil.isBlank(userDto.getPhone())) {
return R.failed("非法参数");
}
String codeObj = redisTemplate.opsForValue().get(CacheConstants.DEFAULT_CODE_KEY + LoginTypeEnum.SMS.getType() + StringPool.AT + userDto.getPhone());
if (!StrUtil.equals(codeObj, code)){
if (!StrUtil.equals(codeObj, code)) {
return R.failed("验证码错误");
}