fix: 用户角色变化强制用户退出

This commit is contained in:
Ray.Hao
2025-05-27 18:29:44 +08:00
parent 3d3e7f8c92
commit 8f9d828205
3 changed files with 58 additions and 44 deletions

View File

@@ -11,11 +11,11 @@ public interface UserRoleService extends IService<UserRole> {
/** /**
* 保存用户角色 * 保存用户角色
* *
* @param userId * @param userId 用户ID
* @param roleIds * @param roleIds 角色ID集合
* @return * @return
*/ */
boolean saveUserRoles(Long userId, List<Long> roleIds); void saveUserRoles(Long userId, List<Long> roleIds);
/** /**
* 判断角色是否存在绑定的用户 * 判断角色是否存在绑定的用户

View File

@@ -3,69 +3,81 @@ package com.youlai.boot.system.service.impl;
import cn.hutool.core.collection.CollectionUtil; import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.boot.core.security.token.TokenManager;
import com.youlai.boot.core.security.util.SecurityUtils;
import com.youlai.boot.system.mapper.UserRoleMapper; import com.youlai.boot.system.mapper.UserRoleMapper;
import com.youlai.boot.system.model.entity.UserRole; import com.youlai.boot.system.model.entity.UserRole;
import com.youlai.boot.system.service.UserRoleService; import com.youlai.boot.system.service.UserRoleService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Service @Service
@RequiredArgsConstructor
public class UserRoleServiceImpl extends ServiceImpl<UserRoleMapper, UserRole> implements UserRoleService { public class UserRoleServiceImpl extends ServiceImpl<UserRoleMapper, UserRole> implements UserRoleService {
private final TokenManager tokenManager;
/** /**
* 保存用户角色 * 保存用户角色
* *
* @param userId * @param userId 用户ID
* @param roleIds * @param roleIds 选择的角色ID集合
* @return * @return
*/ */
@Override @Override
public boolean saveUserRoles(Long userId, List<Long> roleIds) { public void saveUserRoles(Long userId, List<Long> roleIds) {
if (userId == null || CollectionUtil.isEmpty(roleIds)) { if (userId == null || CollectionUtil.isEmpty(roleIds)) {
return false; return ;
} }
// 用户原角色ID集合 // 获取现有角色
List<Long> userRoleIds = this.list(new LambdaQueryWrapper<UserRole>() List<Long> userRoleIds = this.list(new LambdaQueryWrapper<UserRole>()
.select(UserRole::getRoleId)
.eq(UserRole::getUserId, userId)) .eq(UserRole::getUserId, userId))
.stream() .parallelStream()
.map(UserRole::getRoleId) .map(UserRole::getRoleId)
.collect(Collectors.toList()); .toList();
// 新增用户角色 // 使用Set提升对比效率
List<Long> saveRoleIds; Set<Long> oldRoles = new HashSet<>(userRoleIds);
if (CollectionUtil.isEmpty(userRoleIds)) { Set<Long> newRoles = new HashSet<>(roleIds);
saveRoleIds = roleIds;
} else { // 计算变更集
saveRoleIds = roleIds.stream() Set<Long> addedRoles = new HashSet<>(newRoles);
.filter(roleId -> !userRoleIds.contains(roleId)) addedRoles.removeAll(oldRoles);
.collect(Collectors.toList());
Set<Long> removedRoles = new HashSet<>(oldRoles);
removedRoles.removeAll(newRoles);
boolean rolesChanged = !addedRoles.isEmpty() || !removedRoles.isEmpty();
// 批量保存新增角色
if (!addedRoles.isEmpty()) {
this.saveBatch(addedRoles.stream()
.map(roleId -> new UserRole(userId, roleId))
.collect(Collectors.toList()));
} }
List<UserRole> saveUserRoles = saveRoleIds // 删除废弃角色
.stream() if (!removedRoles.isEmpty()) {
.map(roleId -> new UserRole(userId, roleId)) this.remove(new LambdaQueryWrapper<UserRole>()
.collect(Collectors.toList()); .eq(UserRole::getUserId, userId)
this.saveBatch(saveUserRoles); .in(UserRole::getRoleId, removedRoles));
// 删除用户角色
if (CollectionUtil.isNotEmpty(userRoleIds)) {
List<Long> removeRoleIds = userRoleIds.stream()
.filter(roleId -> !roleIds.contains(roleId))
.collect(Collectors.toList());
if (CollectionUtil.isNotEmpty(removeRoleIds)) {
this.remove(new LambdaQueryWrapper<UserRole>()
.eq(UserRole::getUserId, userId)
.in(UserRole::getRoleId, removeRoleIds)
);
}
} }
return true;
// 当权限变更时清除登录态
if (rolesChanged) {
// 获取用户所有有效token根据实际token存储实现
String accessToken = SecurityUtils.getTokenFromRequest();
tokenManager.invalidateToken(accessToken);
}
} }
/** /**

View File

@@ -34,6 +34,7 @@ import com.youlai.boot.system.model.vo.UserPageVO;
import com.youlai.boot.system.model.vo.UserProfileVO; import com.youlai.boot.system.model.vo.UserProfileVO;
import com.youlai.boot.system.service.*; import com.youlai.boot.system.service.*;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate; import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
@@ -51,6 +52,7 @@ import java.util.stream.Collectors;
*/ */
@Service @Service
@RequiredArgsConstructor @RequiredArgsConstructor
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService { public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
private final PasswordEncoder passwordEncoder; private final PasswordEncoder passwordEncoder;
@@ -436,9 +438,9 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
@Override @Override
public boolean sendMobileCode(String mobile) { public boolean sendMobileCode(String mobile) {
// String code = String.valueOf((int) ((Math.random() * 9 + 1) * 1000)); String code = String.valueOf((int) ((Math.random() * 9 + 1) * 1000));
// TODO 为了方便测试,验证码固定为 1234实际开发中在配置了厂商短信服务后可以使用上面的随机验证码
String code = "1234"; log.info("【调试模式】手机号 {} 的验证码为:{}", mobile, code);
Map<String, String> templateParams = new HashMap<>(); Map<String, String> templateParams = new HashMap<>();
templateParams.put("code", code); templateParams.put("code", code);
@@ -500,9 +502,9 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
@Override @Override
public void sendEmailCode(String email) { public void sendEmailCode(String email) {
// String code = String.valueOf((int) ((Math.random() * 9 + 1) * 1000)); String code = String.valueOf((int) ((Math.random() * 9 + 1) * 1000));
// TODO 为了方便测试,验证码固定为 1234实际开发中在配置了邮箱服务后可以使用上面的随机验证码
String code = "1234"; log.info("【调试模式】邮箱 {} 的验证码为:{}", email, code);
mailService.sendMail(email, "邮箱验证码", "您的验证码为:" + code + "请在5分钟内使用"); mailService.sendMail(email, "邮箱验证码", "您的验证码为:" + code + "请在5分钟内使用");
// 缓存验证码5分钟有效用于更换邮箱校验 // 缓存验证码5分钟有效用于更换邮箱校验