feat: 权限缓存加载适配
This commit is contained in:
@@ -67,6 +67,13 @@ ADD INDEX `idx_tenant_id` (`tenant_id`);
|
|||||||
|
|
||||||
UPDATE `sys_role` SET `tenant_id` = 1 WHERE `tenant_id` IS NULL;
|
UPDATE `sys_role` SET `tenant_id` = 1 WHERE `tenant_id` IS NULL;
|
||||||
|
|
||||||
|
-- 角色菜单关联表
|
||||||
|
ALTER TABLE `sys_role_menu`
|
||||||
|
ADD COLUMN `tenant_id` bigint DEFAULT 1 COMMENT '租户ID' AFTER `role_id`,
|
||||||
|
ADD INDEX `idx_role_menu_tenant_id` (`tenant_id`);
|
||||||
|
|
||||||
|
UPDATE `sys_role_menu` SET `tenant_id` = 1 WHERE `tenant_id` IS NULL;
|
||||||
|
|
||||||
-- 部门表
|
-- 部门表
|
||||||
ALTER TABLE `sys_dept`
|
ALTER TABLE `sys_dept`
|
||||||
ADD COLUMN `tenant_id` bigint DEFAULT 1 COMMENT '租户ID' AFTER `id`,
|
ADD COLUMN `tenant_id` bigint DEFAULT 1 COMMENT '租户ID' AFTER `id`,
|
||||||
|
|||||||
@@ -36,6 +36,10 @@ ALTER TABLE `sys_user` ADD UNIQUE KEY `login_name` (`username`);
|
|||||||
ALTER TABLE `sys_role` DROP INDEX `idx_tenant_id`;
|
ALTER TABLE `sys_role` DROP INDEX `idx_tenant_id`;
|
||||||
ALTER TABLE `sys_role` DROP COLUMN `tenant_id`;
|
ALTER TABLE `sys_role` DROP COLUMN `tenant_id`;
|
||||||
|
|
||||||
|
-- 角色菜单关联表
|
||||||
|
ALTER TABLE `sys_role_menu` DROP INDEX `idx_role_menu_tenant_id`;
|
||||||
|
ALTER TABLE `sys_role_menu` DROP COLUMN `tenant_id`;
|
||||||
|
|
||||||
-- 部门表
|
-- 部门表
|
||||||
ALTER TABLE `sys_dept` DROP INDEX `idx_tenant_id`;
|
ALTER TABLE `sys_dept` DROP INDEX `idx_tenant_id`;
|
||||||
ALTER TABLE `sys_dept` DROP COLUMN `tenant_id`;
|
ALTER TABLE `sys_dept` DROP COLUMN `tenant_id`;
|
||||||
|
|||||||
@@ -46,7 +46,6 @@ public class AuthController {
|
|||||||
private final UserService userService;
|
private final UserService userService;
|
||||||
private final TenantService tenantService;
|
private final TenantService tenantService;
|
||||||
private final TenantProperties tenantProperties;
|
private final TenantProperties tenantProperties;
|
||||||
private final PasswordEncoder passwordEncoder;
|
|
||||||
|
|
||||||
@Operation(summary = "获取验证码")
|
@Operation(summary = "获取验证码")
|
||||||
@GetMapping("/captcha")
|
@GetMapping("/captcha")
|
||||||
@@ -75,8 +74,8 @@ public class AuthController {
|
|||||||
return Result.success(authenticationToken);
|
return Result.success(authenticationToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 多租户模式:未指定租户ID,查询该用户名在所有租户下的记录
|
// 多租户模式:未指定租户ID,查询该用户名在所有租户下的账户
|
||||||
List<User> users = userService.listUsersByUsername(username);
|
List<User> users = userService.findUserAcrossAllTenants(username);
|
||||||
|
|
||||||
if (users.isEmpty()) {
|
if (users.isEmpty()) {
|
||||||
return Result.failed("用户不存在");
|
return Result.failed("用户不存在");
|
||||||
|
|||||||
@@ -48,18 +48,5 @@ public class TenantProperties {
|
|||||||
*/
|
*/
|
||||||
private String headerName = "tenant-id";
|
private String headerName = "tenant-id";
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化默认忽略的表
|
|
||||||
*/
|
|
||||||
public TenantProperties() {
|
|
||||||
// 系统表默认忽略多租户
|
|
||||||
ignoreTables.add("sys_tenant");
|
|
||||||
ignoreTables.add("sys_dict");
|
|
||||||
ignoreTables.add("sys_dict_item");
|
|
||||||
ignoreTables.add("sys_config");
|
|
||||||
// 代码生成表(平台共用,不做租户隔离)
|
|
||||||
ignoreTables.add("gen_table");
|
|
||||||
ignoreTables.add("gen_table_column");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package com.youlai.boot.security.service;
|
|||||||
import cn.hutool.core.collection.CollectionUtil;
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.youlai.boot.common.constant.RedisConstants;
|
import com.youlai.boot.common.constant.RedisConstants;
|
||||||
|
import com.youlai.boot.common.tenant.TenantContextHolder;
|
||||||
|
import com.youlai.boot.config.property.TenantProperties;
|
||||||
import com.youlai.boot.security.util.SecurityUtils;
|
import com.youlai.boot.security.util.SecurityUtils;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
@@ -24,6 +26,7 @@ import java.util.*;
|
|||||||
public class PermissionService {
|
public class PermissionService {
|
||||||
|
|
||||||
private final RedisTemplate<String, Object> redisTemplate;
|
private final RedisTemplate<String, Object> redisTemplate;
|
||||||
|
private final TenantProperties tenantProperties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 判断当前登录用户是否拥有操作权限
|
* 判断当前登录用户是否拥有操作权限
|
||||||
@@ -67,21 +70,36 @@ public class PermissionService {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 从缓存中获取角色权限列表
|
* 构建租户权限缓存key
|
||||||
|
*
|
||||||
|
* @param tenantId 租户ID
|
||||||
|
* @return 缓存key
|
||||||
|
*/
|
||||||
|
private String buildRolePermsCacheKey(Long tenantId) {
|
||||||
|
if (!tenantProperties.getEnabled() || tenantId == null) {
|
||||||
|
return RedisConstants.System.ROLE_PERMS;
|
||||||
|
}
|
||||||
|
return RedisConstants.System.ROLE_PERMS + ":" + tenantId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从缓存中获取角色权限列表(兼容单租户和多租户)
|
||||||
*
|
*
|
||||||
* @param roleCodes 角色编码集合
|
* @param roleCodes 角色编码集合
|
||||||
* @return 角色权限列表
|
* @return 角色权限列表
|
||||||
*/
|
*/
|
||||||
public Set<String> getRolePermsFormCache(Set<String> roleCodes) {
|
public Set<String> getRolePermsFormCache(Set<String> roleCodes) {
|
||||||
// 检查输入是否为空
|
|
||||||
if (CollectionUtil.isEmpty(roleCodes)) {
|
if (CollectionUtil.isEmpty(roleCodes)) {
|
||||||
return Collections.emptySet();
|
return Collections.emptySet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取当前租户ID并构建缓存Key
|
||||||
|
Long tenantId = TenantContextHolder.getTenantId();
|
||||||
|
String cacheKey = buildRolePermsCacheKey(tenantId);
|
||||||
|
|
||||||
Set<String> perms = new HashSet<>();
|
Set<String> perms = new HashSet<>();
|
||||||
// 从缓存中一次性获取所有角色的权限
|
|
||||||
Collection<Object> roleCodesAsObjects = new ArrayList<>(roleCodes);
|
Collection<Object> roleCodesAsObjects = new ArrayList<>(roleCodes);
|
||||||
List<Object> rolePermsList = redisTemplate.opsForHash().multiGet(RedisConstants.System.ROLE_PERMS, roleCodesAsObjects);
|
List<Object> rolePermsList = redisTemplate.opsForHash().multiGet(cacheKey, roleCodesAsObjects);
|
||||||
|
|
||||||
for (Object rolePermsObj : rolePermsList) {
|
for (Object rolePermsObj : rolePermsList) {
|
||||||
if (rolePermsObj instanceof Set) {
|
if (rolePermsObj instanceof Set) {
|
||||||
|
|||||||
@@ -43,12 +43,12 @@ public class TenantController {
|
|||||||
*
|
*
|
||||||
* @return 租户列表
|
* @return 租户列表
|
||||||
*/
|
*/
|
||||||
@Operation(summary = "获取当前用户的租户列表")
|
@Operation(summary = "获取当前用户可访问的租户列表")
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public Result<List<TenantVO>> getTenantList() {
|
public Result<List<TenantVO>> getAccessibleTenants() {
|
||||||
Long userId = SecurityUtils.getUserId();
|
Long userId = SecurityUtils.getUserId();
|
||||||
List<TenantVO> tenantList = tenantService.getTenantListByUserId(userId);
|
List<TenantVO> tenantList = tenantService.getAccessibleTenants(userId);
|
||||||
log.info("获取用户 {} 的租户列表,共 {} 个租户", userId, tenantList.size());
|
log.debug("用户 {} 可访问 {} 个租户", userId, tenantList.size());
|
||||||
return Result.success(tenantList);
|
return Result.success(tenantList);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -88,11 +88,10 @@ public class TenantController {
|
|||||||
|
|
||||||
log.info("用户 {} 请求切换租户:{} -> {}", userId, fromTenantId, tenantId);
|
log.info("用户 {} 请求切换租户:{} -> {}", userId, fromTenantId, tenantId);
|
||||||
|
|
||||||
// 验证用户是否有权限访问该租户
|
// 验证用户是否可以访问该租户
|
||||||
boolean hasPermission = tenantService.hasTenantPermission(userId, tenantId);
|
if (!tenantService.canAccessTenant(userId, tenantId)) {
|
||||||
if (!hasPermission) {
|
log.warn("用户 {} 无权访问租户 {}", userId, tenantId);
|
||||||
log.warn("用户 {} 无权限访问租户 {}", userId, tenantId);
|
return Result.failed("无权访问该租户");
|
||||||
return Result.failed("无权限访问该租户");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 验证租户是否存在且正常
|
// 验证租户是否存在且正常
|
||||||
|
|||||||
@@ -13,6 +13,11 @@ import java.util.Set;
|
|||||||
@Data
|
@Data
|
||||||
public class RolePermsBO {
|
public class RolePermsBO {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 租户ID
|
||||||
|
*/
|
||||||
|
private Long tenantId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 角色编码
|
* 角色编码
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -18,11 +18,13 @@ public class User extends BaseEntity {
|
|||||||
*/
|
*/
|
||||||
private String username;
|
private String username;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 昵称
|
* 昵称
|
||||||
*/
|
*/
|
||||||
private String nickname;
|
private String nickname;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 性别((1-男 2-女 0-保密)
|
* 性别((1-男 2-女 0-保密)
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -15,12 +15,15 @@ import java.util.List;
|
|||||||
public interface TenantService extends IService<Tenant> {
|
public interface TenantService extends IService<Tenant> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据用户ID查询用户所属的租户列表
|
* 获取用户可访问的租户列表
|
||||||
|
* <p>
|
||||||
|
* 通过用户名查询该用户在所有租户下的账户,返回可访问的租户列表
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @param userId 用户ID
|
* @param userId 用户ID
|
||||||
* @return 租户列表
|
* @return 可访问的租户列表
|
||||||
*/
|
*/
|
||||||
List<TenantVO> getTenantListByUserId(Long userId);
|
List<TenantVO> getAccessibleTenants(Long userId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据租户ID查询租户信息
|
* 根据租户ID查询租户信息
|
||||||
@@ -39,11 +42,14 @@ public interface TenantService extends IService<Tenant> {
|
|||||||
Long getTenantIdByDomain(String domain);
|
Long getTenantIdByDomain(String domain);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 验证用户是否有权限访问指定租户
|
* 检查用户是否可以访问指定租户
|
||||||
|
* <p>
|
||||||
|
* 验证该用户名在目标租户下是否存在账户
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @param userId 用户ID
|
* @param userId 用户ID
|
||||||
* @param tenantId 租户ID
|
* @param tenantId 租户ID
|
||||||
* @return true-有权限,false-无权限
|
* @return true-可访问,false-不可访问
|
||||||
*/
|
*/
|
||||||
boolean hasTenantPermission(Long userId, Long tenantId);
|
boolean canAccessTenant(Long userId, Long tenantId);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,12 +83,15 @@ public interface UserService extends IService<User> {
|
|||||||
UserAuthCredentials getAuthCredentialsByUsernameAndTenant(String username, Long tenantId);
|
UserAuthCredentials getAuthCredentialsByUsernameAndTenant(String username, Long tenantId);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据用户名查询该用户在所有租户下的记录(用于多租户登录时判断是否需要选择租户)
|
* 跨租户查询用户账户列表
|
||||||
|
* <p>
|
||||||
|
* 查询该用户名在所有租户下的账户记录,用于多租户登录时判断是否需要选择租户
|
||||||
|
* </p>
|
||||||
*
|
*
|
||||||
* @param username 用户名
|
* @param username 用户名
|
||||||
* @return 用户列表(每个租户一条记录)
|
* @return 用户账户列表(每个租户一条记录)
|
||||||
*/
|
*/
|
||||||
List<User> listUsersByUsername(String username);
|
List<User> findUserAcrossAllTenants(String username);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -3,10 +3,11 @@ package com.youlai.boot.system.service.impl;
|
|||||||
import cn.hutool.core.collection.CollectionUtil;
|
import cn.hutool.core.collection.CollectionUtil;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import com.youlai.boot.common.constant.RedisConstants;
|
import com.youlai.boot.common.constant.RedisConstants;
|
||||||
|
import com.youlai.boot.common.tenant.TenantContextHolder;
|
||||||
|
import com.youlai.boot.config.property.TenantProperties;
|
||||||
import com.youlai.boot.system.mapper.RoleMenuMapper;
|
import com.youlai.boot.system.mapper.RoleMenuMapper;
|
||||||
import com.youlai.boot.system.model.bo.RolePermsBO;
|
import com.youlai.boot.system.model.bo.RolePermsBO;
|
||||||
import com.youlai.boot.system.model.entity.RoleMenu;
|
import com.youlai.boot.system.model.entity.RoleMenu;
|
||||||
import com.youlai.boot.common.constant.SecurityConstants;
|
|
||||||
import com.youlai.boot.system.service.RoleMenuService;
|
import com.youlai.boot.system.service.RoleMenuService;
|
||||||
import jakarta.annotation.PostConstruct;
|
import jakarta.annotation.PostConstruct;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
@@ -18,7 +19,7 @@ import java.util.List;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 角色菜单服务实现类
|
* 角色菜单服务实现类(多租户优化版)
|
||||||
*
|
*
|
||||||
* @author Ray.Hao
|
* @author Ray.Hao
|
||||||
* @since 2.5.0
|
* @since 2.5.0
|
||||||
@@ -29,76 +30,159 @@ import java.util.Set;
|
|||||||
public class RoleMenuServiceImpl extends ServiceImpl<RoleMenuMapper, RoleMenu> implements RoleMenuService {
|
public class RoleMenuServiceImpl extends ServiceImpl<RoleMenuMapper, RoleMenu> implements RoleMenuService {
|
||||||
|
|
||||||
private final RedisTemplate<String, Object> redisTemplate;
|
private final RedisTemplate<String, Object> redisTemplate;
|
||||||
|
private final TenantProperties tenantProperties;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化权限缓存
|
* 构建租户权限缓存key
|
||||||
|
*
|
||||||
|
* @param tenantId 租户ID
|
||||||
|
* @return 缓存key
|
||||||
|
* - 多租户开启: system:role:perms:{tenantId}
|
||||||
|
* - 多租户关闭: system:role:perms
|
||||||
*/
|
*/
|
||||||
@PostConstruct
|
private String buildRolePermsCacheKey(Long tenantId) {
|
||||||
public void initRolePermsCache() {
|
// 判断是否启用多租户
|
||||||
log.info("初始化权限缓存... ");
|
if (!tenantProperties.getEnabled() || tenantId == null) {
|
||||||
refreshRolePermsCache();
|
// 单租户模式或多租户未开启:使用原有Key
|
||||||
|
return RedisConstants.System.ROLE_PERMS;
|
||||||
|
}
|
||||||
|
// 多租户模式开启:Key按租户隔离
|
||||||
|
return RedisConstants.System.ROLE_PERMS + ":" + tenantId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 刷新权限缓存
|
* 启动时初始化权限缓存
|
||||||
|
*/
|
||||||
|
@PostConstruct
|
||||||
|
public void initRolePermsCache() {
|
||||||
|
log.info("开始初始化权限缓存...");
|
||||||
|
|
||||||
|
List<RolePermsBO> allRolePermsList = this.baseMapper.getRolePermsList(null);
|
||||||
|
|
||||||
|
if (CollectionUtil.isEmpty(allRolePermsList)) {
|
||||||
|
log.warn("权限数据为空,跳过缓存初始化");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tenantProperties.getEnabled()) {
|
||||||
|
// 多租户模式:按租户分组缓存
|
||||||
|
allRolePermsList.forEach(rolePerms -> {
|
||||||
|
Long tenantId = rolePerms.getTenantId();
|
||||||
|
if (tenantId == null) {
|
||||||
|
log.warn("多租户模式下,角色[{}]缺少tenantId,跳过", rolePerms.getRoleCode());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
String cacheKey = RedisConstants.System.ROLE_PERMS + ":" + tenantId;
|
||||||
|
String roleCode = rolePerms.getRoleCode();
|
||||||
|
Set<String> perms = rolePerms.getPerms();
|
||||||
|
|
||||||
|
if (CollectionUtil.isNotEmpty(perms)) {
|
||||||
|
redisTemplate.opsForHash().put(cacheKey, roleCode, perms);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
log.info("权限缓存初始化完成(多租户模式),共{}条数据", allRolePermsList.size());
|
||||||
|
} else {
|
||||||
|
// 单租户模式:所有数据统一缓存
|
||||||
|
String cacheKey = RedisConstants.System.ROLE_PERMS;
|
||||||
|
allRolePermsList.forEach(rolePerms -> {
|
||||||
|
String roleCode = rolePerms.getRoleCode();
|
||||||
|
Set<String> perms = rolePerms.getPerms();
|
||||||
|
|
||||||
|
if (CollectionUtil.isNotEmpty(perms)) {
|
||||||
|
redisTemplate.opsForHash().put(cacheKey, roleCode, perms);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
log.info("权限缓存初始化完成(单租户模式),共{}条数据", allRolePermsList.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新当前租户权限缓存
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void refreshRolePermsCache() {
|
public void refreshRolePermsCache() {
|
||||||
// 清理权限缓存
|
Long tenantId = TenantContextHolder.getTenantId();
|
||||||
redisTemplate.opsForHash().delete(RedisConstants.System.ROLE_PERMS, "*");
|
String cacheKey = buildRolePermsCacheKey(tenantId);
|
||||||
|
|
||||||
|
// 清理当前租户权限缓存
|
||||||
|
redisTemplate.delete(cacheKey);
|
||||||
|
|
||||||
|
// 重新加载当前租户权限
|
||||||
List<RolePermsBO> list = this.baseMapper.getRolePermsList(null);
|
List<RolePermsBO> list = this.baseMapper.getRolePermsList(null);
|
||||||
if (CollectionUtil.isNotEmpty(list)) {
|
if (CollectionUtil.isNotEmpty(list)) {
|
||||||
list.forEach(item -> {
|
list.forEach(item -> {
|
||||||
String roleCode = item.getRoleCode();
|
String roleCode = item.getRoleCode();
|
||||||
Set<String> perms = item.getPerms();
|
Set<String> perms = item.getPerms();
|
||||||
if (CollectionUtil.isNotEmpty(perms)) {
|
if (CollectionUtil.isNotEmpty(perms)) {
|
||||||
redisTemplate.opsForHash().put(RedisConstants.System.ROLE_PERMS, roleCode, perms);
|
redisTemplate.opsForHash().put(cacheKey, roleCode, perms);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if (tenantId == null) {
|
||||||
/**
|
log.info("权限缓存刷新完成(单租户模式)");
|
||||||
* 刷新权限缓存
|
} else {
|
||||||
*/
|
log.info("租户[{}]权限缓存刷新完成", tenantId);
|
||||||
@Override
|
|
||||||
public void refreshRolePermsCache(String roleCode) {
|
|
||||||
// 清理权限缓存
|
|
||||||
redisTemplate.opsForHash().delete(RedisConstants.System.ROLE_PERMS, roleCode);
|
|
||||||
|
|
||||||
List<RolePermsBO> list = this.baseMapper.getRolePermsList(roleCode);
|
|
||||||
if (CollectionUtil.isNotEmpty(list)) {
|
|
||||||
RolePermsBO rolePerms = list.get(0);
|
|
||||||
if (rolePerms == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<String> perms = rolePerms.getPerms();
|
|
||||||
if (CollectionUtil.isNotEmpty(perms)) {
|
|
||||||
redisTemplate.opsForHash().put(RedisConstants.System.ROLE_PERMS, roleCode, perms);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 刷新权限缓存 (角色编码变更时调用)
|
* 刷新单个角色权限缓存
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void refreshRolePermsCache(String roleCode) {
|
||||||
|
Long tenantId = TenantContextHolder.getTenantId();
|
||||||
|
String cacheKey = buildRolePermsCacheKey(tenantId);
|
||||||
|
|
||||||
|
// 清理指定角色缓存
|
||||||
|
redisTemplate.opsForHash().delete(cacheKey, roleCode);
|
||||||
|
|
||||||
|
// 重新加载指定角色权限
|
||||||
|
List<RolePermsBO> list = this.baseMapper.getRolePermsList(roleCode);
|
||||||
|
if (CollectionUtil.isNotEmpty(list)) {
|
||||||
|
RolePermsBO rolePerms = list.get(0);
|
||||||
|
if (rolePerms != null) {
|
||||||
|
Set<String> perms = rolePerms.getPerms();
|
||||||
|
if (CollectionUtil.isNotEmpty(perms)) {
|
||||||
|
redisTemplate.opsForHash().put(cacheKey, roleCode, perms);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tenantId == null) {
|
||||||
|
log.info("角色[{}]权限缓存刷新完成(单租户模式)", roleCode);
|
||||||
|
} else {
|
||||||
|
log.info("租户[{}]角色[{}]权限缓存刷新完成", tenantId, roleCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新权限缓存(角色编码变更时调用)
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public void refreshRolePermsCache(String oldRoleCode, String newRoleCode) {
|
public void refreshRolePermsCache(String oldRoleCode, String newRoleCode) {
|
||||||
|
Long tenantId = TenantContextHolder.getTenantId();
|
||||||
|
String cacheKey = buildRolePermsCacheKey(tenantId);
|
||||||
|
|
||||||
// 清理旧角色权限缓存
|
// 清理旧角色权限缓存
|
||||||
redisTemplate.opsForHash().delete(RedisConstants.System.ROLE_PERMS, oldRoleCode);
|
redisTemplate.opsForHash().delete(cacheKey, oldRoleCode);
|
||||||
|
|
||||||
// 添加新角色权限缓存
|
// 添加新角色权限缓存
|
||||||
List<RolePermsBO> list = this.baseMapper.getRolePermsList(newRoleCode);
|
List<RolePermsBO> list = this.baseMapper.getRolePermsList(newRoleCode);
|
||||||
if (CollectionUtil.isNotEmpty(list)) {
|
if (CollectionUtil.isNotEmpty(list)) {
|
||||||
RolePermsBO rolePerms = list.get(0);
|
RolePermsBO rolePerms = list.get(0);
|
||||||
if (rolePerms == null) {
|
if (rolePerms != null) {
|
||||||
return;
|
Set<String> perms = rolePerms.getPerms();
|
||||||
|
if (CollectionUtil.isNotEmpty(perms)) {
|
||||||
|
redisTemplate.opsForHash().put(cacheKey, newRoleCode, perms);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Set<String> perms = rolePerms.getPerms();
|
|
||||||
redisTemplate.opsForHash().put(RedisConstants.System.ROLE_PERMS, newRoleCode, perms);
|
if (tenantId == null) {
|
||||||
|
log.info("角色编码变更: {} -> {},权限缓存已更新(单租户模式)", oldRoleCode, newRoleCode);
|
||||||
|
} else {
|
||||||
|
log.info("租户[{}]角色编码变更: {} -> {},权限缓存已更新", tenantId, oldRoleCode, newRoleCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,6 +194,7 @@ public class RoleMenuServiceImpl extends ServiceImpl<RoleMenuMapper, RoleMenu> i
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Set<String> getRolePermsByRoleCodes(Set<String> roles) {
|
public Set<String> getRolePermsByRoleCodes(Set<String> roles) {
|
||||||
|
// 直接查询数据库(保持原有逻辑)
|
||||||
return this.baseMapper.listRolePerms(roles);
|
return this.baseMapper.listRolePerms(roles);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ public class TenantServiceImpl extends ServiceImpl<TenantMapper, Tenant> impleme
|
|||||||
private final UserMapper userMapper;
|
private final UserMapper userMapper;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TenantVO> getTenantListByUserId(Long userId) {
|
public List<TenantVO> getAccessibleTenants(Long userId) {
|
||||||
// 临时忽略租户过滤,查询所有租户
|
// 临时忽略租户过滤,查询所有租户
|
||||||
TenantContextHolder.setIgnoreTenant(true);
|
TenantContextHolder.setIgnoreTenant(true);
|
||||||
try {
|
try {
|
||||||
@@ -123,7 +123,7 @@ public class TenantServiceImpl extends ServiceImpl<TenantMapper, Tenant> impleme
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean hasTenantPermission(Long userId, Long tenantId) {
|
public boolean canAccessTenant(Long userId, Long tenantId) {
|
||||||
TenantContextHolder.setIgnoreTenant(true);
|
TenantContextHolder.setIgnoreTenant(true);
|
||||||
try {
|
try {
|
||||||
// 先根据用户ID查询用户信息(获取 username)
|
// 先根据用户ID查询用户信息(获取 username)
|
||||||
|
|||||||
@@ -271,15 +271,15 @@ public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements Us
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<User> listUsersByUsername(String username) {
|
public List<User> findUserAcrossAllTenants(String username) {
|
||||||
// 临时忽略租户过滤,查询该用户名在所有租户下的记录
|
// 临时忽略租户过滤,查询该用户名在所有租户下的账户记录
|
||||||
TenantContextHolder.setIgnoreTenant(true);
|
TenantContextHolder.setIgnoreTenant(true);
|
||||||
try {
|
try {
|
||||||
return this.list(
|
return this.list(
|
||||||
new LambdaQueryWrapper<User>()
|
new LambdaQueryWrapper<User>()
|
||||||
.eq(User::getUsername, username)
|
.eq(User::getUsername, username)
|
||||||
.eq(User::getIsDeleted, 0)
|
.eq(User::getIsDeleted, 0)
|
||||||
.orderByAsc(User::getTenantId) // 按租户ID排序,优先返回较小的租户ID
|
.orderByAsc(User::getTenantId)
|
||||||
);
|
);
|
||||||
} finally {
|
} finally {
|
||||||
TenantContextHolder.setIgnoreTenant(false);
|
TenantContextHolder.setIgnoreTenant(false);
|
||||||
|
|||||||
@@ -288,9 +288,11 @@ youlai:
|
|||||||
|
|
||||||
# 忽略多租户过滤的表名列表(系统表、租户表等不需要租户隔离的表)
|
# 忽略多租户过滤的表名列表(系统表、租户表等不需要租户隔离的表)
|
||||||
ignore-tables:
|
ignore-tables:
|
||||||
- sys_tenant # 租户表本身
|
- sys_tenant # 租户表本身
|
||||||
- sys_menu # 菜单表(功能入口定义,所有租户共享)
|
- sys_menu # 菜单表(功能入口定义,所有租户共享)
|
||||||
- sys_dict # 字典表(通常共享)
|
- sys_dict # 字典表(通常共享)
|
||||||
- sys_dict_item # 字典项表(通常共享)
|
- sys_dict_item # 字典项表(通常共享)
|
||||||
- sys_config # 系统配置表(通常共享)
|
- sys_config # 系统配置表(通常共享)
|
||||||
|
- gen_table # 代码生成表(平台共用)
|
||||||
|
- gen_table_column # 代码生成字段表(平台共用)
|
||||||
# ============================================
|
# ============================================
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
|
|
||||||
<!-- 权限和拥有权限的角色的映射 -->
|
<!-- 权限和拥有权限的角色的映射 -->
|
||||||
<resultMap id="PremRolesMap" type="com.youlai.boot.system.model.bo.RolePermsBO">
|
<resultMap id="PremRolesMap" type="com.youlai.boot.system.model.bo.RolePermsBO">
|
||||||
|
<result property="tenantId" column="tenant_id"/>
|
||||||
<result property="roleCode" column="role_code"/>
|
<result property="roleCode" column="role_code"/>
|
||||||
<collection property="perms" ofType="string" javaType="java.util.Set">
|
<collection property="perms" ofType="string" javaType="java.util.Set">
|
||||||
<result column="perm"/>
|
<result column="perm"/>
|
||||||
@@ -26,8 +27,9 @@
|
|||||||
<!-- 获取权限和拥有权限的角色列表 -->
|
<!-- 获取权限和拥有权限的角色列表 -->
|
||||||
<select id="getRolePermsList" resultMap="PremRolesMap">
|
<select id="getRolePermsList" resultMap="PremRolesMap">
|
||||||
SELECT
|
SELECT
|
||||||
t3.perm,
|
t2.tenant_id,
|
||||||
t2.`code` role_code
|
t2.`code` role_code,
|
||||||
|
t3.perm
|
||||||
FROM
|
FROM
|
||||||
`sys_role_menu` t1
|
`sys_role_menu` t1
|
||||||
INNER JOIN sys_role t2 ON t1.role_id = t2.id AND t2.is_deleted = 0 AND t2.`status` = 1
|
INNER JOIN sys_role t2 ON t1.role_id = t2.id AND t2.is_deleted = 0 AND t2.`status` = 1
|
||||||
|
|||||||
Reference in New Issue
Block a user