diff --git a/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java b/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java index a442863..d9e97f4 100644 --- a/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java +++ b/dl_admin/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java @@ -4,6 +4,8 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; + +import com.ruoyi.framework.web.service.TokenService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.web.bind.annotation.DeleteMapping; @@ -38,6 +40,9 @@ public class SysUserOnlineController extends BaseController @Autowired private RedisCache redisCache; + @Autowired + private TokenService tokenService; + @PreAuthorize("@ss.hasPermi('monitor:online:list')") @GetMapping("/list") public TableDataInfo list(String ipaddr, String userName) @@ -77,7 +82,7 @@ public class SysUserOnlineController extends BaseController @DeleteMapping("/{tokenId}") public AjaxResult forceLogout(@PathVariable String tokenId) { - redisCache.deleteObject(CacheConstants.LOGIN_TOKEN_KEY + tokenId); + tokenService.forceLogout(tokenId); return success(); } } diff --git a/dl_admin/ruoyi-admin/src/main/resources/application.yml b/dl_admin/ruoyi-admin/src/main/resources/application.yml index 4e0f832..2797699 100644 --- a/dl_admin/ruoyi-admin/src/main/resources/application.yml +++ b/dl_admin/ruoyi-admin/src/main/resources/application.yml @@ -156,6 +156,8 @@ aliyun: # 登录相关配置 login: + # 登录缓存 + cache-enable: true # 是否限制单用户登录 single: true diff --git a/dl_admin/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java b/dl_admin/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java index 0080343..3dbe493 100644 --- a/dl_admin/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java +++ b/dl_admin/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java @@ -12,6 +12,11 @@ public class CacheConstants */ public static final String LOGIN_TOKEN_KEY = "login_tokens:"; + /** + * 登录用户id redis key 用于实现灵活控制多设备登录 + */ + public static final String LOGIN_USER_ID_KEY = "login_user_ids:"; + /** * 验证码 redis key */ diff --git a/dl_admin/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java b/dl_admin/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java index 2f89a91..61b8630 100644 --- a/dl_admin/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java +++ b/dl_admin/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java @@ -44,7 +44,7 @@ public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler { String userName = loginUser.getUsername(); // 删除用户缓存记录 - tokenService.delLoginUser(loginUser.getToken()); + tokenService.delLoginUser(loginUser.getToken(), loginUser.getUserId()); // 记录用户退出日志 AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, MessageUtils.message("user.logout.success"))); } diff --git a/dl_admin/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java b/dl_admin/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java index 588d69d..99ed374 100644 --- a/dl_admin/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java +++ b/dl_admin/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java @@ -45,6 +45,9 @@ public class TokenService @Value("${token.expireTime}") private int expireTime; + @Value("${login.single}") + private boolean isSingle; + protected static final long MILLIS_SECOND = 1000; protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND; @@ -96,15 +99,36 @@ public class TokenService /** * 删除用户身份信息 */ - public void delLoginUser(String token) + public void delLoginUser(String token, Long userId) { - if (StringUtils.isNotEmpty(token)) - { + if (StringUtils.isNotEmpty(token)) { String userKey = getTokenKey(token); redisCache.deleteObject(userKey); } + if (userId != null) { + String userIdKey = getUserKey(userId); + redisCache.deleteObject(userIdKey); + } + } + /** + * 强制退出 + * + * @param tokenId token(uuid) + */ + public void forceLogout(String tokenId){ + String userKey = getTokenKey(tokenId); + if(isSingle){//多设备登录相关控制代码 + LoginUser loginUser = redisCache.getCacheObject(userKey); + Long userId = loginUser.getUserId(); + String userIdKey = getUserKey(userId); + redisCache.deleteObject(userIdKey); + } + redisCache.deleteObject(userKey); + } + + /** * 创建令牌 * @@ -147,15 +171,44 @@ public class TokenService */ public void refreshToken(LoginUser loginUser) { + //如果是单点登录,则退出当前用户 + if (isSingle) { + String userIdKey = getUserKey(loginUser.getUserId()); + LoginUser user = redisCache.getCacheObject(userIdKey); + if (user != null){ + String userKey = getTokenKey(user.getToken()); + if (StringUtils.isNotEmpty(userKey)) { + redisCache.deleteObject(userIdKey); + redisCache.deleteObject(userKey); + } + } + } loginUser.setLoginTime(System.currentTimeMillis()); + //todo 令牌有效期 loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE); // 根据uuid将loginUser缓存 String userKey = getTokenKey(loginUser.getToken()); // redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES); /* vinjor 永不过期,适配小程序*/ redisCache.setCacheObject(userKey, loginUser); + //如果是单点登录,则记录用户idkey对应的用户信息key + if (isSingle){ + String userIdKey = getUserKey(loginUser.getUserId()); + redisCache.setCacheObject(userIdKey, loginUser); + } } + /** + * 获取用户Key + * + * @param userId 当前登录用户的主键id + * @return + */ + private String getUserKey(Long userId) { + return CacheConstants.LOGIN_USER_ID_KEY + userId; + } + + /** * 设置用户代理信息 * diff --git a/dl_vue/src/permission.js b/dl_vue/src/permission.js index 24c542e..e24d966 100644 --- a/dl_vue/src/permission.js +++ b/dl_vue/src/permission.js @@ -36,7 +36,7 @@ router.beforeEach((to, from, next) => { watermark.remove() // 设置新水印 - const currentUser = store.getters.name || '未知用户' + const currentUser = store.getters.nickName || '未知用户' const currentDate = new Date().toLocaleDateString() watermark.set({ text: `${currentUser}\n${currentDate}`, @@ -63,7 +63,7 @@ router.beforeEach((to, from, next) => { watermark.remove() // 设置新水印 - const currentUser = store.getters.name || '未知用户' + const currentUser = store.getters.nickName || '未知用户' const currentDate = new Date().toLocaleDateString() watermark.set({ text: `${currentUser}\n${currentDate}`,