refactor: 用户权限方案重构,黑名单实现 JWT 主动注销

This commit is contained in:
haoxr
2024-01-25 16:40:31 +08:00
parent 5b72b3af97
commit 911af69c0d
20 changed files with 232 additions and 116 deletions

View File

@@ -6,11 +6,14 @@ import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import java.time.LocalDateTime;
@Data
public class BaseEntity implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@TableField(fill = FieldFill.INSERT)

View File

@@ -14,9 +14,9 @@ import lombok.Data;
@Schema
public class BasePageQuery {
@Schema(description = "页码", required = true, example = "1")
@Schema(description = "页码", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private int pageNum = 1;
@Schema(description = "每页记录数", required = true, example = "10")
@Schema(description = "每页记录数", requiredMode = Schema.RequiredMode.REQUIRED, example = "10")
private int pageSize = 10;
}

View File

@@ -3,6 +3,7 @@ package com.youlai.system.common.base;
import lombok.Data;
import lombok.ToString;
import java.io.Serial;
import java.io.Serializable;
/**
@@ -15,5 +16,6 @@ import java.io.Serializable;
@ToString
public class BaseVO implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
}

View File

@@ -1,8 +1,9 @@
package com.youlai.system.plugin.captcha;
package com.youlai.system.config;
import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.captcha.generator.MathGenerator;
import cn.hutool.captcha.generator.RandomGenerator;
import com.youlai.system.plugin.captcha.CaptchaProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

View File

@@ -1,10 +1,11 @@
package com.youlai.system.config;
import com.youlai.system.common.constant.SecurityConstants;
import cn.hutool.captcha.generator.CodeGenerator;
import com.youlai.system.security.constant.SecurityConstants;
import com.youlai.system.security.exception.MyAccessDeniedHandler;
import com.youlai.system.security.exception.MyAuthenticationEntryPoint;
import com.youlai.system.filter.JwtTokenFilter;
import com.youlai.system.filter.VerifyCodeFilter;
import com.youlai.system.filter.JwtValidationFilter;
import com.youlai.system.filter.CaptchaValidationFilter;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -37,6 +38,8 @@ public class SecurityConfig {
private final MyAuthenticationEntryPoint authenticationEntryPoint;
private final MyAccessDeniedHandler accessDeniedHandler;
private final RedisTemplate<String, Object> redisTemplate;
private final CodeGenerator codeGenerator;
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
@@ -56,9 +59,9 @@ public class SecurityConfig {
;
// 验证码校验过滤器
http.addFilterBefore(new VerifyCodeFilter(), UsernamePasswordAuthenticationFilter.class);
http.addFilterBefore(new CaptchaValidationFilter(redisTemplate,codeGenerator), UsernamePasswordAuthenticationFilter.class);
// JWT 校验过滤器
http.addFilterBefore(new JwtTokenFilter(redisTemplate), UsernamePasswordAuthenticationFilter.class);
http.addFilterBefore(new JwtValidationFilter(redisTemplate), UsernamePasswordAuthenticationFilter.class);
return http.build();
}

View File

@@ -10,7 +10,6 @@ import com.youlai.system.model.query.RolePageQuery;
import com.youlai.system.model.vo.RolePageVO;
import com.youlai.system.service.SysRoleService;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.security.SecurityRequirement;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import lombok.RequiredArgsConstructor;
@@ -76,7 +75,7 @@ public class SysRoleController {
@DeleteMapping("/{ids}")
@PreAuthorize("@ss.hasPerm('sys:role:delete')")
public Result deleteRoles(
@Parameter(description = "删除角色,多个以英文逗号(,)分割") @PathVariable String ids
@Parameter(description = "删除角色,多个以英文逗号(,)拼接") @PathVariable String ids
) {
boolean result = roleService.deleteRoles(ids);
return Result.judge(result);

View File

@@ -102,7 +102,7 @@ public class SysUserController {
@Operation(summary = "修改用户密码")
@PatchMapping(value = "/{userId}/password")
@PreAuthorize("@ss.hasPerm('sys:user:reset_pwd')")
@PreAuthorize("@ss.hasPerm('sys:user:password:edit')")
public Result updatePassword(
@Parameter(description = "用户ID") @PathVariable Long userId,
@RequestParam String password

View File

@@ -1,17 +1,16 @@
package com.youlai.system.filter;
import cn.hutool.captcha.generator.MathGenerator;
import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.spring.SpringUtil;
import com.youlai.system.common.constant.CacheConstants;
import com.youlai.system.common.constant.SecurityConstants;
import com.youlai.system.security.constant.SecurityConstants;
import com.youlai.system.common.result.ResultCode;
import com.youlai.system.common.util.ResponseUtils;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.web.filter.OncePerRequestFilter;
@@ -19,39 +18,47 @@ import java.io.IOException;
/**
* 验证码校验过滤器
* 图形验证码校验过滤器
*
* @author haoxr
* @since 2022/10/1
*/
public class VerifyCodeFilter extends OncePerRequestFilter {
public class CaptchaValidationFilter extends OncePerRequestFilter {
private static final AntPathRequestMatcher LOGIN_PATH_REQUEST_MATCHER = new AntPathRequestMatcher(SecurityConstants.LOGIN_PATH, "POST");
public static final String CAPTCHA_CODE_PARAM_NAME = "captchaCode";
public static final String CAPTCHA_KEY_PARAM_NAME = "captchaKey";
private final RedisTemplate<String, Object> redisTemplate;
private final CodeGenerator codeGenerator;
public CaptchaValidationFilter(RedisTemplate<String, Object> redisTemplate, CodeGenerator codeGenerator) {
this.redisTemplate = redisTemplate;
this.codeGenerator = codeGenerator;
}
@Override
public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
// 检验登录接口的验证码
if (LOGIN_PATH_REQUEST_MATCHER.matches(request)) {
// 请求中的验证码
String verifyCode = request.getParameter(CAPTCHA_CODE_PARAM_NAME);
String captchaCode = request.getParameter(CAPTCHA_CODE_PARAM_NAME);
// TODO 兼容没有验证码的版本(线上请移除这个判断)
if (StrUtil.isBlank(verifyCode)) {
if (StrUtil.isBlank(captchaCode)) {
chain.doFilter(request, response);
return;
}
// 缓存中的验证码
StringRedisTemplate redisTemplate = SpringUtil.getBean("stringRedisTemplate", StringRedisTemplate.class);
String verifyCodeKey = request.getParameter(CAPTCHA_KEY_PARAM_NAME);
String cacheVerifyCode = redisTemplate.opsForValue().get(CacheConstants.CAPTCHA_CODE_PREFIX + verifyCodeKey);
String cacheVerifyCode = (String) redisTemplate.opsForValue().get(CacheConstants.CAPTCHA_CODE_PREFIX + verifyCodeKey);
if (cacheVerifyCode == null) {
ResponseUtils.writeErrMsg(response, ResultCode.VERIFY_CODE_TIMEOUT);
} else {
// 验证码比对
MathGenerator mathGenerator = new MathGenerator();
if (mathGenerator.verify(cacheVerifyCode, verifyCode)) {
if (codeGenerator.verify(cacheVerifyCode, captchaCode)) {
chain.doFilter(request, response);
} else {
ResponseUtils.writeErrMsg(response, ResultCode.VERIFY_CODE_ERROR);

View File

@@ -22,16 +22,16 @@ import java.io.IOException;
import java.util.Map;
/**
* JWT token 过滤器
* JWT token 校验过滤器
*
* @author haoxr
* @since 2023/9/13
*/
public class JwtTokenFilter extends OncePerRequestFilter {
public class JwtValidationFilter extends OncePerRequestFilter {
private final RedisTemplate<String, Object> redisTemplate;
public JwtTokenFilter(RedisTemplate<String, Object> redisTemplate) {
public JwtValidationFilter(RedisTemplate<String, Object> redisTemplate) {
this.redisTemplate = redisTemplate;
}

View File

@@ -1,4 +1,4 @@
package com.youlai.system.common.constant;
package com.youlai.system.security.constant;
/**
* JWT Claims声明常量
@@ -15,11 +15,6 @@ public interface JwtClaimConstants {
*/
String USER_ID = "userId";
/**
* 用户名
*/
String USERNAME = "username";
/**
* 部门ID
*/

View File

@@ -1,4 +1,4 @@
package com.youlai.system.common.constant;
package com.youlai.system.security.constant;
/**
* Security 常量

View File

@@ -13,8 +13,7 @@ import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.PatternMatchUtils;
import java.util.List;
import java.util.Set;
import java.util.*;
/**
* SpringSecurity 权限校验
@@ -27,10 +26,105 @@ import java.util.Set;
@Slf4j
public class PermissionService {
private final RedisTemplate redisTemplate;
private final RedisTemplate<String,Object> redisTemplate;
private final SysRoleMenuService roleMenuService;
/**
* 初始化权限缓存
*/
@PostConstruct
public void initRolePermsCache() {
refreshRolePermsCache();
}
/**
* 刷新权限缓存
*/
public void refreshRolePermsCache() {
// 清理权限缓存
redisTemplate.opsForHash().delete(CacheConstants.ROLE_PERMS_PREFIX, "*");
List<RolePermsBO> list = roleMenuService.getRolePermsList(null);
if (CollectionUtil.isNotEmpty(list)) {
list.forEach(item -> {
String roleCode = item.getRoleCode();
Set<String> perms = item.getPerms();
redisTemplate.opsForHash().put(CacheConstants.ROLE_PERMS_PREFIX, roleCode, perms);
});
}
}
/**
* 刷新权限缓存
*/
public void refreshRolePermsCache(String roleCode) {
// 清理权限缓存
redisTemplate.opsForHash().delete(CacheConstants.ROLE_PERMS_PREFIX, roleCode);
List<RolePermsBO> list = roleMenuService.getRolePermsList(roleCode);
if (CollectionUtil.isNotEmpty(list)) {
RolePermsBO rolePerms = list.get(0);
if (rolePerms == null) {
return;
}
Set<String> perms = rolePerms.getPerms();
redisTemplate.opsForHash().put(CacheConstants.ROLE_PERMS_PREFIX, roleCode, perms);
}
}
/**
* 刷新权限缓存 (角色编码变更时调用)
*/
public void refreshRolePermsCache(String oldRoleCode,String newRoleCode) {
// 清理旧角色权限缓存
redisTemplate.opsForHash().delete(CacheConstants.ROLE_PERMS_PREFIX, oldRoleCode);
// 添加新角色权限缓存
List<RolePermsBO> list = roleMenuService.getRolePermsList(newRoleCode);
if (CollectionUtil.isNotEmpty(list)) {
RolePermsBO rolePerms = list.get(0);
if (rolePerms == null) {
return;
}
Set<String> perms = rolePerms.getPerms();
redisTemplate.opsForHash().put(CacheConstants.ROLE_PERMS_PREFIX, newRoleCode, perms);
}
}
/**
* 获取角色权限列表
*
* @param roleCodes 角色编码集合
* @return 角色权限列表
*/
public Set<String> getRolePermsFormCache(Set<String> roleCodes) {
// 检查输入是否为空
if (CollectionUtil.isEmpty(roleCodes)) {
return Collections.emptySet();
}
Set<String> perms = new HashSet<>();
// 从缓存中一次性获取所有角色的权限
Collection<Object> roleCodesAsObjects = new ArrayList<>(roleCodes);
List<Object> rolePermsList = redisTemplate.opsForHash().multiGet(CacheConstants.ROLE_PERMS_PREFIX, roleCodesAsObjects);
for (Object rolePermsObj : rolePermsList) {
if (rolePermsObj instanceof Set) {
@SuppressWarnings("unchecked")
Set<String> rolePerms = (Set<String>) rolePermsObj;
perms.addAll(rolePerms);
}
}
return perms;
}
/**
* 判断当前登录用户是否拥有操作权限
*
@@ -62,7 +156,6 @@ public class PermissionService {
// 匹配权限,支持通配符
hasPermission = rolePerms.stream()
.anyMatch(rolePerm ->
//rolePerm=sys:user:* requiredPerm=sys:user:add 返回true
PatternMatchUtils.simpleMatch(rolePerm, requiredPerm)
);
@@ -77,48 +170,5 @@ public class PermissionService {
return hasPermission;
}
/**
* 初始化权限缓存
*/
@PostConstruct
public void initPermissionCache() {
refreshPermissionCache();
}
/**
* 刷新权限缓存
*/
public void refreshPermissionCache() {
// 清理权限缓存
redisTemplate.opsForHash().delete(CacheConstants.ROLE_PERMS_PREFIX, "*");
List<RolePermsBO> list = roleMenuService.getRolePermsList(null);
if (CollectionUtil.isNotEmpty(list)) {
list.forEach(item -> {
String roleCode = item.getRoleCode();
Set<String> perms = item.getPerms();
redisTemplate.opsForHash().put(CacheConstants.ROLE_PERMS_PREFIX, roleCode, perms);
});
}
}
/**
* 刷新权限缓存
*/
public void refreshPermissionCache(String roleCode) {
// 清理权限缓存
redisTemplate.opsForHash().delete(CacheConstants.ROLE_PERMS_PREFIX, roleCode);
List<RolePermsBO> list = roleMenuService.getRolePermsList(roleCode);
if (CollectionUtil.isNotEmpty(list)) {
RolePermsBO rolePerms = list.get(0);
if (rolePerms == null) {
return;
}
Set<String> perms = rolePerms.getPerms();
redisTemplate.opsForHash().put(CacheConstants.ROLE_PERMS_PREFIX, roleCode, perms);
}
}
}

View File

@@ -8,7 +8,7 @@ import cn.hutool.json.JSONArray;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTPayload;
import cn.hutool.jwt.JWTUtil;
import com.youlai.system.common.constant.JwtClaimConstants;
import com.youlai.system.security.constant.JwtClaimConstants;
import com.youlai.system.security.model.SysUserDetails;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -29,9 +29,15 @@ import java.util.stream.Collectors;
@Component
public class JwtUtils {
/**
* JWT 加解密使用的密钥
*/
private static byte[] key;
/**
* JWT Token 的有效时间(单位:秒)
*/
private static int ttl;
@@ -57,7 +63,6 @@ public class JwtUtils {
SysUserDetails userDetails = (SysUserDetails) authentication.getPrincipal();
Map<String, Object> payload = new HashMap<>();
payload.put(JwtClaimConstants.USER_ID, userDetails.getUserId()); // 用户ID
payload.put(JwtClaimConstants.DEPT_ID, userDetails.getDeptId()); // 部门ID

View File

@@ -17,7 +17,7 @@ import com.youlai.system.security.util.JwtUtils;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -43,7 +43,7 @@ import java.util.concurrent.TimeUnit;
public class AuthServiceImpl implements AuthService {
private final AuthenticationManager authenticationManager;
private final StringRedisTemplate redisTemplate;
private final RedisTemplate<String,Object> redisTemplate;
private final CodeGenerator codeGenerator;
private final Font captchaFont;
private final CaptchaProperties captchaProperties;

View File

@@ -18,6 +18,7 @@ import com.youlai.system.model.form.MenuForm;
import com.youlai.system.model.query.MenuQuery;
import com.youlai.system.model.vo.MenuVO;
import com.youlai.system.model.vo.RouteVO;
import com.youlai.system.security.service.PermissionService;
import com.youlai.system.service.SysMenuService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
@@ -42,6 +43,8 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
private final MenuConverter menuConverter;
private final PermissionService permissionService;
/**
* 菜单列表
@@ -199,18 +202,17 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
@Override
@CacheEvict(cacheNames = "menu", key = "'routes'")
public boolean saveMenu(MenuForm menuForm) {
String path = menuForm.getPath();
MenuTypeEnum menuType = menuForm.getType();
// 如果是目录
if (menuType == MenuTypeEnum.CATALOG) {
if (menuType == MenuTypeEnum.CATALOG) { // 如果是外链
String path = menuForm.getPath();
if (menuForm.getParentId() == 0 && !path.startsWith("/")) {
menuForm.setPath("/" + path); // 一级目录需以 / 开头
}
menuForm.setComponent("Layout");
}
// 如果是外链
else if (menuType == MenuTypeEnum.EXTLINK) {
} else if (menuType == MenuTypeEnum.EXTLINK) { // 如果是目录
menuForm.setComponent(null);
}
@@ -218,7 +220,14 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
String treePath = generateMenuTreePath(menuForm.getParentId());
entity.setTreePath(treePath);
return this.saveOrUpdate(entity);
boolean result = this.saveOrUpdate(entity);
if (result) {
// 编辑刷新角色权限缓存
if (menuForm.getId() != null) {
permissionService.refreshRolePermsCache();
}
}
return result;
}
/**
@@ -285,10 +294,18 @@ public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> impl
@Override
@CacheEvict(cacheNames = "menu", key = "'routes'")
public boolean deleteMenu(Long id) {
return this.remove(new LambdaQueryWrapper<SysMenu>()
.eq(SysMenu::getId, id)
.or()
.apply("CONCAT (',',tree_path,',') LIKE CONCAT('%,',{0},',%')", id));
boolean result = this.remove(new LambdaQueryWrapper<SysMenu>()
.eq(SysMenu::getId, id)
.or()
.apply("CONCAT (',',tree_path,',') LIKE CONCAT('%,',{0},',%')", id));
// 刷新角色权限缓存
if (result) {
permissionService.refreshRolePermsCache();
}
return result;
}

View File

@@ -2,31 +2,33 @@ package com.youlai.system.service.impl;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.youlai.system.common.constant.SystemConstants;
import com.youlai.system.common.model.Option;
import com.youlai.system.security.util.SecurityUtils;
import com.youlai.system.converter.RoleConverter;
import com.youlai.system.security.service.PermissionService;
import com.youlai.system.mapper.SysRoleMapper;
import com.youlai.system.model.entity.SysRole;
import com.youlai.system.model.entity.SysRoleMenu;
import com.youlai.system.model.form.RoleForm;
import com.youlai.system.model.query.RolePageQuery;
import com.youlai.system.model.vo.RolePageVO;
import com.youlai.system.security.service.PermissionService;
import com.youlai.system.service.SysRoleMenuService;
import com.youlai.system.service.SysRoleService;
import com.youlai.system.service.SysUserRoleService;
import com.youlai.system.security.util.SecurityUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
/**
* 角色业务实现类
@@ -100,19 +102,37 @@ public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> impl
public boolean saveRole(RoleForm roleForm) {
Long roleId = roleForm.getId();
String roleCode = roleForm.getCode();
// 编辑角色时,判断角色是否存在
SysRole oldRole = null;
if (roleId != null) {
oldRole = this.getById(roleId);
Assert.isTrue(oldRole != null, "角色不存在");
}
String roleCode = roleForm.getCode();
long count = this.count(new LambdaQueryWrapper<SysRole>()
.ne(roleId != null, SysRole::getId, roleId)
.and(wrapper ->
wrapper.eq(SysRole::getCode, roleCode).or().eq(SysRole::getName, roleForm.getName())
));
Assert.isTrue(count == 0, "角色名称或角色编码重复,请检查");
Assert.isTrue(count == 0, "角色名称或角色编码已存在,请修改后重试");
// 实体转换
SysRole role = roleConverter.form2Entity(roleForm);
return this.saveOrUpdate(role);
boolean result = this.saveOrUpdate(role);
if (result) {
// 判断角色编码或状态是否修改,修改了则刷新权限缓存
if (oldRole != null
&& (
!StrUtil.equals(oldRole.getCode(), roleCode) ||
!ObjectUtil.equals(oldRole.getStatus(), roleForm.getStatus())
)) {
permissionService.refreshRolePermsCache(oldRole.getCode(), roleCode);
}
}
return result;
}
/**
@@ -136,9 +156,16 @@ public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> impl
*/
@Override
public boolean updateRoleStatus(Long roleId, Integer status) {
return this.update(new LambdaUpdateWrapper<SysRole>()
.eq(SysRole::getId, roleId)
.set(SysRole::getStatus, status));
SysRole role = this.getById(roleId);
Assert.isTrue(role != null, "角色不存在");
boolean result = this.updateById(role);
if (result) {
// 刷新角色的权限缓存
permissionService.refreshRolePermsCache(role.getCode());
}
return result;
}
/**
@@ -163,9 +190,9 @@ public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> impl
Assert.isTrue(!isRoleAssigned, "角色【{}】已分配用户,请先解除关联后删除", role.getName());
boolean deleteResult = this.removeById(roleId);
if(deleteResult) {
if (deleteResult) {
// 删除成功,刷新权限缓存
permissionService.refreshPermissionCache(role.getCode());
permissionService.refreshRolePermsCache(role.getCode());
}
}
return true;
@@ -193,8 +220,14 @@ public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> impl
@Transactional
@CacheEvict(cacheNames = "menu", key = "'routes'")
public boolean assignMenusToRole(Long roleId, List<Long> menuIds) {
SysRole role = this.getById(roleId);
Assert.isTrue(role != null, "角色不存在");
// 删除角色菜单
roleMenuService.remove(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, roleId));
roleMenuService.remove(
new LambdaQueryWrapper<SysRoleMenu>()
.eq(SysRoleMenu::getRoleId, roleId)
);
// 新增角色菜单
if (CollectionUtil.isNotEmpty(menuIds)) {
List<SysRoleMenu> roleMenus = menuIds
@@ -203,6 +236,10 @@ public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> impl
.toList();
roleMenuService.saveBatch(roleMenus);
}
// 刷新角色的权限缓存
permissionService.refreshRolePermsCache(role.getCode());
return true;
}

View File

@@ -22,9 +22,9 @@ import com.youlai.system.model.query.UserPageQuery;
import com.youlai.system.model.vo.UserExportVO;
import com.youlai.system.model.vo.UserInfoVO;
import com.youlai.system.model.vo.UserPageVO;
import com.youlai.system.security.service.PermissionService;
import com.youlai.system.service.*;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -54,7 +54,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
private final SysRoleService roleService;
private final RedisTemplate redisTemplate;
private final PermissionService permissionService;
/**
* 获取用户分页列表
@@ -254,7 +254,7 @@ public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> impl
// 用户权限集合
if (CollectionUtil.isNotEmpty(roles)) {
Set<String> perms = menuService.listRolePerms(roles);
Set<String> perms = permissionService.getRolePermsFormCache(roles);
userInfoVO.setPerms(perms);
}
return userInfoVO;