1. 抽取获取在线用户(可获取指定tenantId下用户)

2. 停用租户时,将所有租户下的用户token清空
This commit is contained in:
warden 2023-06-20 11:36:24 +08:00
parent eb807fae94
commit 0fcd369232
6 changed files with 129 additions and 34 deletions

View File

@ -12,6 +12,15 @@ import org.dromara.common.tenant.helper.TenantHelper;
*/
public class TenantKeyPrefixHandler extends KeyPrefixHandler {
// 用于获取指定租户下的缓存
private static final ThreadLocal<String> 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,11 @@ 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();
if (tenantId == null) {
tenantId = TenantHelper.getTenantId();
}
if (StringUtils.startsWith(name, tenantId)) {
// 如果存在则直接返回
return super.map(name);

View File

@ -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<SysUserOnline> list(String ipaddr, String userName) {
// 获取所有未过期的 token
List<String> keys = StpUtil.searchTokenValue("", 0, -1, false);
List<UserOnlineDTO> 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<UserOnlineDTO> userOnlineDTOList = this.onlineService.getOnlineUsers(null, userBo);
// 倒序排序
Collections.reverse(userOnlineDTOList);
userOnlineDTOList.removeAll(Collections.singleton(null));
List<SysUserOnline> userOnlineList = BeanUtil.copyToList(userOnlineDTOList, SysUserOnline.class);
return TableDataInfo.build(userOnlineList);
}

View File

@ -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;
}

View File

@ -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<UserOnlineDTO> getOnlineUsers(String tenantId, SysOnlineUserBo userBo);
}

View File

@ -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<UserOnlineDTO> 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);
}

View File

@ -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<UserOnlineDTO> getOnlineUsers(String tenantId, SysOnlineUserBo userBo) {
String ipaddr = userBo == null ? null : userBo.getIpaddr();
String userName = userBo == null ? null : userBo.getUserName();
// 获取所有未过期的 token
List<String> keys = StpUtil.searchTokenValue("", 0, -1, false);
List<UserOnlineDTO> 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;
}
}