diff --git a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/handle/TenantKeyPrefixHandler.java b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/handle/TenantKeyPrefixHandler.java index c9c2f9529..9e35c8d19 100644 --- a/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/handle/TenantKeyPrefixHandler.java +++ b/ruoyi-common/ruoyi-common-tenant/src/main/java/org/dromara/common/tenant/handle/TenantKeyPrefixHandler.java @@ -12,6 +12,15 @@ import org.dromara.common.tenant.helper.TenantHelper; */ public class TenantKeyPrefixHandler extends KeyPrefixHandler { + // 用于获取指定租户下的缓存 + private static final ThreadLocal TENANT_ID = new ThreadLocal<>(); + + public static void setTenantId(String tenantId) { + if (StringUtils.isNotEmpty(tenantId)) { + TENANT_ID.set(tenantId); + } + } + public TenantKeyPrefixHandler(String keyPrefix) { super(keyPrefix); } @@ -27,7 +36,12 @@ public class TenantKeyPrefixHandler extends KeyPrefixHandler { if (StringUtils.contains(name, GlobalConstants.GLOBAL_REDIS_KEY)) { return super.map(name); } - String tenantId = TenantHelper.getTenantId(); + + String tenantId = TENANT_ID.get(); + TENANT_ID.remove(); + if (tenantId == null) { + tenantId = TenantHelper.getTenantId(); + } if (StringUtils.startsWith(name, tenantId)) { // 如果存在则直接返回 return super.map(name); diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java index c3f09773b..30a873dd7 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java @@ -4,22 +4,18 @@ import cn.dev33.satoken.annotation.SaCheckPermission; import cn.dev33.satoken.exception.NotLoginException; import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.bean.BeanUtil; -import org.dromara.common.core.constant.CacheConstants; -import org.dromara.common.core.constant.GlobalConstants; +import lombok.RequiredArgsConstructor; import org.dromara.common.core.domain.R; import org.dromara.common.core.domain.dto.UserOnlineDTO; -import org.dromara.common.core.utils.StreamUtils; -import org.dromara.common.core.utils.StringUtils; import org.dromara.common.log.annotation.Log; import org.dromara.common.log.enums.BusinessType; import org.dromara.common.mybatis.core.page.TableDataInfo; -import org.dromara.common.redis.utils.RedisUtils; import org.dromara.common.web.core.BaseController; import org.dromara.system.domain.SysUserOnline; -import lombok.RequiredArgsConstructor; +import org.dromara.system.domain.bo.SysOnlineUserBo; +import org.dromara.system.service.ISysUserOnlineService; import org.springframework.web.bind.annotation.*; -import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -33,6 +29,8 @@ import java.util.List; @RequestMapping("/monitor/online") public class SysUserOnlineController extends BaseController { + private final ISysUserOnlineService onlineService; + /** * 获取在线用户监控列表 * @@ -42,33 +40,12 @@ public class SysUserOnlineController extends BaseController { @SaCheckPermission("monitor:online:list") @GetMapping("/list") public TableDataInfo list(String ipaddr, String userName) { - // 获取所有未过期的 token - List keys = StpUtil.searchTokenValue("", 0, -1, false); - List userOnlineDTOList = new ArrayList<>(); - for (String key : keys) { - String token = StringUtils.substringAfterLast(key, ":"); - // 如果已经过期则跳过 - if (StpUtil.stpLogic.getTokenActivityTimeoutByToken(token) < -1) { - continue; - } - userOnlineDTOList.add(RedisUtils.getCacheObject(CacheConstants.ONLINE_TOKEN_KEY + token)); - } - if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName)) { - userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline -> - StringUtils.equals(ipaddr, userOnline.getIpaddr()) && - StringUtils.equals(userName, userOnline.getUserName()) - ); - } else if (StringUtils.isNotEmpty(ipaddr)) { - userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline -> - StringUtils.equals(ipaddr, userOnline.getIpaddr()) - ); - } else if (StringUtils.isNotEmpty(userName)) { - userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline -> - StringUtils.equals(userName, userOnline.getUserName()) - ); - } + SysOnlineUserBo userBo = new SysOnlineUserBo(); + userBo.setIpaddr(ipaddr); + userBo.setUserName(userName); + List userOnlineDTOList = this.onlineService.getOnlineUsers(null, userBo); + // 倒序排序 Collections.reverse(userOnlineDTOList); - userOnlineDTOList.removeAll(Collections.singleton(null)); List userOnlineList = BeanUtil.copyToList(userOnlineDTOList, SysUserOnline.class); return TableDataInfo.build(userOnlineList); } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOnlineUserBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOnlineUserBo.java new file mode 100644 index 000000000..bd6553385 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOnlineUserBo.java @@ -0,0 +1,14 @@ +package org.dromara.system.domain.bo; + +import lombok.Data; + +/** + * @Author warden + * @Date 2023/6/19 17:34 + */ +@Data +public class SysOnlineUserBo { + private String ipaddr; + private String userName; +// private String tenantId; +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserOnlineService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserOnlineService.java new file mode 100644 index 000000000..b4544f9a3 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserOnlineService.java @@ -0,0 +1,13 @@ +package org.dromara.system.service; + +import org.dromara.common.core.domain.dto.UserOnlineDTO; +import org.dromara.system.domain.bo.SysOnlineUserBo; + +import java.util.List; + +/** + * @Author warden + */ +public interface ISysUserOnlineService { + List getOnlineUsers(String tenantId, SysOnlineUserBo userBo); +} diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java index eb681519a..42ac97b05 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java @@ -1,6 +1,8 @@ package org.dromara.system.service.impl; +import cn.dev33.satoken.exception.NotLoginException; import cn.dev33.satoken.secure.BCrypt; +import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.convert.Convert; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.RandomUtil; @@ -11,6 +13,7 @@ import lombok.RequiredArgsConstructor; import org.dromara.common.core.constant.CacheNames; import org.dromara.common.core.constant.Constants; import org.dromara.common.core.constant.TenantConstants; +import org.dromara.common.core.domain.dto.UserOnlineDTO; import org.dromara.common.core.exception.ServiceException; import org.dromara.common.core.utils.MapstructUtils; import org.dromara.common.core.utils.SpringUtils; @@ -18,10 +21,12 @@ import org.dromara.common.core.utils.StringUtils; import org.dromara.common.mybatis.core.page.PageQuery; import org.dromara.common.mybatis.core.page.TableDataInfo; import org.dromara.system.domain.*; +import org.dromara.system.domain.bo.SysOnlineUserBo; import org.dromara.system.domain.bo.SysTenantBo; import org.dromara.system.domain.vo.SysTenantVo; import org.dromara.system.mapper.*; import org.dromara.system.service.ISysTenantService; +import org.dromara.system.service.ISysUserOnlineService; import org.springframework.cache.annotation.CacheEvict; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; @@ -52,6 +57,7 @@ public class SysTenantServiceImpl implements ISysTenantService { private final SysDictTypeMapper dictTypeMapper; private final SysDictDataMapper dictDataMapper; private final SysConfigMapper configMapper; + private final ISysUserOnlineService onlineService; /** * 查询租户 @@ -261,6 +267,17 @@ public class SysTenantServiceImpl implements ISysTenantService { @CacheEvict(cacheNames = CacheNames.SYS_TENANT, key = "#bo.tenantId") @Override public int updateTenantStatus(SysTenantBo bo) { + // 停用租户时,要将租户下的所有在线用户全部剔除,避免依然有权限操作 + if (Constants.FAIL.equals(bo.getStatus())) { + List userOnlineDTOList = this.onlineService.getOnlineUsers(bo.getTenantId(), null); + for (UserOnlineDTO online : userOnlineDTOList) { + try { + StpUtil.kickoutByTokenValue(online.getTokenId()); + } catch (NotLoginException ignored) { + } + } + } + SysTenant tenant = MapstructUtils.convert(bo, SysTenant.class); return baseMapper.updateById(tenant); } diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserOnlineServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserOnlineServiceImpl.java new file mode 100644 index 000000000..29e18b613 --- /dev/null +++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserOnlineServiceImpl.java @@ -0,0 +1,61 @@ +package org.dromara.system.service.impl; + + +import cn.dev33.satoken.stp.StpUtil; +import org.dromara.common.core.constant.CacheConstants; +import org.dromara.common.core.domain.dto.UserOnlineDTO; +import org.dromara.common.core.utils.StreamUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.redis.utils.RedisUtils; +import org.dromara.common.tenant.handle.TenantKeyPrefixHandler; +import org.dromara.system.domain.bo.SysOnlineUserBo; +import org.dromara.system.service.ISysUserOnlineService; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +@Service +public class SysUserOnlineServiceImpl implements ISysUserOnlineService { + + @Override + public List getOnlineUsers(String tenantId, SysOnlineUserBo userBo) { + String ipaddr = userBo == null ? null : userBo.getIpaddr(); + String userName = userBo == null ? null : userBo.getUserName(); + // 获取所有未过期的 token + List keys = StpUtil.searchTokenValue("", 0, -1, false); + List userOnlineDTOList = new ArrayList<>(); + for (String key : keys) { + String token = StringUtils.substringAfterLast(key, ":"); + // 如果已经过期则跳过 + if (StpUtil.stpLogic.getTokenActivityTimeoutByToken(token) < -1) { + continue; + } + + TenantKeyPrefixHandler.setTenantId(tenantId); + UserOnlineDTO online = RedisUtils.getCacheObject(CacheConstants.ONLINE_TOKEN_KEY + token); + + if (online != null) { + userOnlineDTOList.add(online); + } + } +// // 清空为空的数据 +// userOnlineDTOList.removeAll(Collections.singleton(null)); + if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName)) { + userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline -> + StringUtils.equals(ipaddr, userOnline.getIpaddr()) && + StringUtils.equals(userName, userOnline.getUserName()) + ); + } else if (StringUtils.isNotEmpty(ipaddr)) { + userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline -> + StringUtils.equals(ipaddr, userOnline.getIpaddr()) + ); + } else if (StringUtils.isNotEmpty(userName)) { + userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline -> + StringUtils.equals(userName, userOnline.getUserName()) + ); + } + + return userOnlineDTOList; + } +}