Skip to content

Commit

Permalink
chore: release 1.0.5
Browse files Browse the repository at this point in the history
fix: 修复在多租户下,token到期时无法清理在线用户状态
perf: 升级ruoyi-ui依赖
  • Loading branch information
yixiaco committed Jul 14, 2023
1 parent cbef01f commit 2e6cadb
Show file tree
Hide file tree
Showing 9 changed files with 249 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,6 @@ public void logout() {
TenantHelper.clearDynamic();
}
recordLogininfor(loginUser.getTenantId(), loginUser.getUsername(), Constants.LOGOUT, MessageUtils.message("user.logout.success"));
MultipleStpUtil.SYSTEM.logout();
}
} catch (NotLoginException ignored) {
} finally {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public interface GlobalConstants {
String PWD_ERR_CNT_KEY = GLOBAL_REDIS_KEY + "pwd_err_cnt:";

/**
* 应用key redis key
* 应用key redis map key
*/
String APP_KEY = GLOBAL_REDIS_KEY + "app_key";

Expand All @@ -42,6 +42,11 @@ public interface GlobalConstants {
*/
String SOCIAL_AUTH_CODE_KEY = GLOBAL_REDIS_KEY + "social_auth_codes:";

/**
* 在线租户id redis key
*/
String ONLINE_TOKEN_TENANT_ID_KEY = GLOBAL_REDIS_KEY + "online_token_tenant_id:";

/**
* 获取全局key
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,12 @@
import cn.dev33.satoken.config.SaTokenConfig;
import cn.dev33.satoken.listener.SaTokenListener;
import cn.dev33.satoken.stp.SaLoginModel;
import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.constant.CacheConstants;
import org.dromara.common.core.domain.dto.UserOnlineDTO;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.enums.UserType;
import org.dromara.common.core.utils.ServletUtils;
import org.dromara.common.core.utils.ip.AddressUtils;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.satoken.online.OnlineUserCacheManagerInterface;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.time.Duration;

/**
* 用户行为 侦听器的实现
*
Expand All @@ -30,6 +20,8 @@ public class UserActionListener implements SaTokenListener {

@Autowired
private SaTokenConfig tokenConfig;
@Autowired
private OnlineUserCacheManagerInterface onlineUserCacheManager;

/**
* 每次登录时触发
Expand All @@ -38,22 +30,10 @@ public class UserActionListener implements SaTokenListener {
public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) {
UserType userType = UserType.getUserType(loginId.toString());
if (userType == UserType.SYS_USER) {
UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent"));
String ip = ServletUtils.getClientIP();
LoginUser user = LoginHelper.getUser();
UserOnlineDTO dto = new UserOnlineDTO();
dto.setIpaddr(ip);
dto.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
dto.setBrowser(userAgent.getBrowser().getName());
dto.setOs(userAgent.getOs().getName());
dto.setLoginTime(System.currentTimeMillis());
dto.setTokenId(tokenValue);
dto.setUserName(user.getUsername());
dto.setDeptName(user.getDeptName());
if(tokenConfig.getTimeout() == -1) {
RedisUtils.setObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto);
if (tokenConfig.getTimeout() == -1) {
onlineUserCacheManager.setCache(userType, tokenValue, loginModel);
} else {
RedisUtils.setObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto, Duration.ofSeconds(tokenConfig.getTimeout()));
onlineUserCacheManager.setCache(userType, tokenValue, loginModel, tokenConfig.getTimeout());
}
log.info("user doLogin, userId:{}, token:{}", loginId, tokenValue);
} else if (userType == UserType.APP_USER) {
Expand All @@ -66,7 +46,7 @@ public void doLogin(String loginType, Object loginId, String tokenValue, SaLogin
*/
@Override
public void doLogout(String loginType, Object loginId, String tokenValue) {
RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
onlineUserCacheManager.deleteCache(loginType, loginId, tokenValue);
log.info("user doLogout, userId:{}, token:{}", loginId, tokenValue);
}

Expand All @@ -75,7 +55,7 @@ public void doLogout(String loginType, Object loginId, String tokenValue) {
*/
@Override
public void doKickout(String loginType, Object loginId, String tokenValue) {
RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
onlineUserCacheManager.deleteCache(loginType, loginId, tokenValue);
log.info("user doKickout, userId:{}, token:{}", loginId, tokenValue);
}

Expand All @@ -84,7 +64,7 @@ public void doKickout(String loginType, Object loginId, String tokenValue) {
*/
@Override
public void doReplaced(String loginType, Object loginId, String tokenValue) {
RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
onlineUserCacheManager.deleteCache(loginType, loginId, tokenValue);
log.info("user doReplaced, userId:{}, token:{}", loginId, tokenValue);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package org.dromara.common.satoken.online;

import cn.dev33.satoken.stp.SaLoginModel;
import org.dromara.common.core.constant.CacheConstants;
import org.dromara.common.core.domain.dto.UserOnlineDTO;
import org.dromara.common.core.enums.UserType;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.utils.OnlineUserUtil;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.stereotype.Component;

import java.time.Duration;

/**
* 默认在线登录缓存管理
*
* @author hexm
* @date 2023/07/14 17:22
*/
@Component
@ConditionalOnMissingBean(OnlineUserCacheManagerInterface.class)
public class DefaultOnlineUserCacheManager implements OnlineUserCacheManagerInterface {

/**
* 保存在线用户
*
* @param userType 用户类型
* @param tokenValue token值
* @param loginModel 登录对象
*/
@Override
public void setCache(UserType userType, String tokenValue, SaLoginModel loginModel) {
UserOnlineDTO dto = OnlineUserUtil.getOnlineDTO(tokenValue);
RedisUtils.setObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto);
}

/**
* 保存在线用户
*
* @param userType 用户类型
* @param tokenValue token值
* @param loginModel 登录对象
* @param timeout 超时时间
*/
@Override
public void setCache(UserType userType, String tokenValue, SaLoginModel loginModel, Long timeout) {
UserOnlineDTO dto = OnlineUserUtil.getOnlineDTO(tokenValue);
RedisUtils.setObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto, Duration.ofSeconds(timeout));
}

/**
* 删除缓存
*
* @param loginType 登录类型
* @param loginId 用户id
* @param tokenValue token值
*/
@Override
public void deleteCache(String loginType, Object loginId, String tokenValue) {
RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package org.dromara.common.satoken.online;

import cn.dev33.satoken.stp.SaLoginModel;
import org.dromara.common.core.enums.UserType;

/**
* 在线用户管理
*
* @author hexm
* @date 2023/07/14 17:14
*/
public interface OnlineUserCacheManagerInterface {

/**
* 保存在线用户
*
* @param userType 用户类型
* @param tokenValue token值
* @param loginModel 登录对象
*/
void setCache(UserType userType, String tokenValue, SaLoginModel loginModel);

/**
* 保存在线用户
*
* @param userType 用户类型
* @param tokenValue token值
* @param loginModel 登录对象
* @param timeout 超时时间
*/
void setCache(UserType userType, String tokenValue, SaLoginModel loginModel, Long timeout);

/**
* 删除缓存
*
* @param loginType 登录类型
* @param loginId 用户id
* @param tokenValue token值
*/
void deleteCache(String loginType, Object loginId, String tokenValue);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package org.dromara.common.satoken.utils;

import cn.hutool.http.useragent.UserAgent;
import cn.hutool.http.useragent.UserAgentUtil;
import org.dromara.common.core.domain.dto.UserOnlineDTO;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.utils.ServletUtils;
import org.dromara.common.core.utils.ip.AddressUtils;

/**
* @author hexm
* @date 2023/07/14 17:30
*/
public class OnlineUserUtil {

/**
* 获取在线登录用户对象
*
* @param tokenValue token值
* @return
*/
public static UserOnlineDTO getOnlineDTO(String tokenValue) {
UserAgent userAgent = UserAgentUtil.parse(ServletUtils.getRequest().getHeader("User-Agent"));
String ip = ServletUtils.getClientIP();
LoginUser user = LoginHelper.getUser();
UserOnlineDTO dto = new UserOnlineDTO();
dto.setIpaddr(ip);
dto.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
dto.setBrowser(userAgent.getBrowser().getName());
dto.setOs(userAgent.getOs().getName());
dto.setLoginTime(System.currentTimeMillis());
dto.setTokenId(tokenValue);
dto.setUserName(user.getUsername());
dto.setDeptName(user.getDeptName());
return dto;
}
}
5 changes: 5 additions & 0 deletions ruoyi-common/ruoyi-common-tenant/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@
<artifactId>transmittable-thread-local</artifactId>
</dependency>

<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-satoken</artifactId>
</dependency>

</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package org.dromara.common.tenant.online;

import cn.dev33.satoken.stp.SaLoginModel;
import cn.hutool.core.util.StrUtil;
import org.dromara.common.core.constant.CacheConstants;
import org.dromara.common.core.constant.GlobalConstants;
import org.dromara.common.core.domain.dto.UserOnlineDTO;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.enums.UserType;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.satoken.online.OnlineUserCacheManagerInterface;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.common.satoken.utils.OnlineUserUtil;
import org.dromara.common.tenant.helper.TenantHelper;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

import java.time.Duration;

/**
* 租户在线用户缓存管理
*
* @author hexm
* @date 2023/07/14 17:29
*/
@Primary
@Component
public class TenantOnlineUserCacheManager implements OnlineUserCacheManagerInterface {

/**
* 保存在线用户
*
* @param userType 用户类型
* @param tokenValue token值
* @param loginModel 登录对象
*/
@Override
public void setCache(UserType userType, String tokenValue, SaLoginModel loginModel) {
UserOnlineDTO dto = OnlineUserUtil.getOnlineDTO(tokenValue);
LoginUser user = LoginHelper.getUser();
RedisUtils.setObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto);
RedisUtils.setObject(GlobalConstants.ONLINE_TOKEN_TENANT_ID_KEY + tokenValue, user.getTenantId());
}

/**
* 保存在线用户
*
* @param userType 用户类型
* @param tokenValue token值
* @param loginModel 登录对象
* @param timeout 超时时间
*/
@Override
public void setCache(UserType userType, String tokenValue, SaLoginModel loginModel, Long timeout) {
LoginUser user = LoginHelper.getUser();
UserOnlineDTO dto = OnlineUserUtil.getOnlineDTO(tokenValue);
RedisUtils.setObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue, dto, Duration.ofSeconds(timeout));
RedisUtils.setObject(GlobalConstants.ONLINE_TOKEN_TENANT_ID_KEY + tokenValue, user.getTenantId(), Duration.ofSeconds(timeout));
}

/**
* 删除缓存
*
* @param loginType 登录类型
* @param loginId 用户id
* @param tokenValue token值
*/
@Override
public void deleteCache(String loginType, Object loginId, String tokenValue) {
String tenantId = RedisUtils.getObject(GlobalConstants.ONLINE_TOKEN_TENANT_ID_KEY + tokenValue);
if (StrUtil.isNotBlank(tenantId)) {
try {
TenantHelper.setDynamic(tenantId);
RedisUtils.deleteObject(CacheConstants.ONLINE_TOKEN_KEY + tokenValue);
TenantHelper.clearDynamic();
} finally {
RedisUtils.deleteObject(GlobalConstants.ONLINE_TOKEN_TENANT_ID_KEY + tokenValue);
}
}
}
}
Loading

0 comments on commit 2e6cadb

Please sign in to comment.