【sa-token】登录和退出换写法

This commit is contained in:
JEECG
2025-10-16 11:06:47 +08:00
parent c85bb1f62d
commit 468af57489
6 changed files with 119 additions and 110 deletions

View File

@ -7,8 +7,8 @@ import jakarta.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.StringUtils;
import org.jeecg.common.api.vo.Result; import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant; import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.system.util.JwtUtil; import org.jeecg.common.util.LoginUserUtils;
import org.jeecg.common.util.RedisUtil; import org.jeecg.common.util.RedisUtil;
import org.jeecg.modules.cas.util.CasServiceUtil; import org.jeecg.modules.cas.util.CasServiceUtil;
import org.jeecg.modules.cas.util.XmlUtils; import org.jeecg.modules.cas.util.XmlUtils;
@ -16,6 +16,7 @@ import org.jeecg.modules.system.entity.SysDepart;
import org.jeecg.modules.system.entity.SysUser; import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.service.ISysDepartService; import org.jeecg.modules.system.service.ISysDepartService;
import org.jeecg.modules.system.service.ISysUserService; import org.jeecg.modules.system.service.ISysUserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value; import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity; import org.springframework.http.HttpEntity;
@ -78,10 +79,10 @@ public class CasClientController {
if(!result.isSuccess()) { if(!result.isSuccess()) {
return result; return result;
} }
String token = JwtUtil.sign(sysUser.getUsername(), sysUser.getPassword()); // 使用Sa-Token生成token使用username作为loginId
// 设置超时时间 LoginUser loginUser = new LoginUser();
redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token); BeanUtils.copyProperties(sysUser, loginUser);
redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME*2 / 1000); String token = LoginUserUtils.doLogin(loginUser);
//获取用户部门信息 //获取用户部门信息
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();

View File

@ -6,10 +6,12 @@ import org.apache.commons.lang3.ObjectUtils;
import org.jeecg.common.api.dto.message.MessageDTO; import org.jeecg.common.api.dto.message.MessageDTO;
import org.jeecg.common.constant.CommonConstant; import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.enums.MessageTypeEnum; import org.jeecg.common.constant.enums.MessageTypeEnum;
import org.jeecg.common.system.util.JwtUtil; import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.LoginUserUtils;
import org.jeecg.common.util.RedisUtil; import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.SpringContextUtils; import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.common.util.oConvertUtils; import org.jeecg.common.util.oConvertUtils;
import org.springframework.beans.BeanUtils;
import org.jeecg.config.StaticConfig; import org.jeecg.config.StaticConfig;
import org.jeecg.modules.message.entity.SysMessage; import org.jeecg.modules.message.entity.SysMessage;
import org.jeecg.modules.message.handle.ISendMsgHandle; import org.jeecg.modules.message.handle.ISendMsgHandle;
@ -240,12 +242,10 @@ public class EmailSendMsgHandle implements ISendMsgHandle {
* @return * @return
*/ */
private String getToken(SysUser user) { private String getToken(SysUser user) {
// 生成token // 使用封装方法:一步完成登录和设置用户信息
String token = JwtUtil.sign(user.getUsername(), user.getPassword()); LoginUser loginUser = new LoginUser();
redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token); BeanUtils.copyProperties(user, loginUser);
// 设置超时时间 1个小时 return LoginUserUtils.doLogin(loginUser);
redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 1 / 1000);
return token;
} }
/** /**

View File

@ -7,11 +7,13 @@ import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import jakarta.servlet.http.HttpServletRequest;
import org.jeecg.common.api.vo.Result; import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CommonConstant; import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.base.controller.JeecgController; import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.system.query.QueryGenerator; import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.system.util.JwtUtil; import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.LoginUserUtils;
import org.jeecg.common.util.RedisUtil; import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.RestUtil; import org.jeecg.common.util.RestUtil;
import org.jeecg.modules.openapi.entity.OpenApi; import org.jeecg.modules.openapi.entity.OpenApi;
@ -24,6 +26,7 @@ import org.jeecg.modules.openapi.service.OpenApiService;
import org.jeecg.modules.openapi.swagger.*; import org.jeecg.modules.openapi.swagger.*;
import org.jeecg.modules.system.entity.SysUser; import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.service.ISysUserService; import org.jeecg.modules.system.service.ISysUserService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity; import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
@ -33,7 +36,6 @@ import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate; import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.util.UriComponentsBuilder;
import jakarta.servlet.http.HttpServletRequest;
import java.net.URI; import java.net.URI;
import java.util.*; import java.util.*;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@ -163,7 +165,7 @@ public class OpenApiController extends JeecgController<OpenApi, OpenApiService>
String appkey = request.getHeader("appkey"); String appkey = request.getHeader("appkey");
OpenApiAuth openApiAuth = openApiAuthService.getByAppkey(appkey); OpenApiAuth openApiAuth = openApiAuthService.getByAppkey(appkey);
SysUser systemUser = sysUserService.getUserByName(openApiAuth.getCreateBy()); SysUser systemUser = sysUserService.getUserByName(openApiAuth.getCreateBy());
String token = this.getToken(systemUser.getUsername(), systemUser.getPassword()); String token = this.getToken(systemUser);
httpHeaders.put("X-Access-Token", Lists.newArrayList(token)); httpHeaders.put("X-Access-Token", Lists.newArrayList(token));
httpHeaders.put("Content-Type",Lists.newArrayList("application/json")); httpHeaders.put("Content-Type",Lists.newArrayList("application/json"));
HttpEntity<String> httpEntity = new HttpEntity<>(json, httpHeaders); HttpEntity<String> httpEntity = new HttpEntity<>(json, httpHeaders);
@ -202,15 +204,13 @@ public class OpenApiController extends JeecgController<OpenApi, OpenApiService>
/** /**
* 生成接口访问令牌 Token * 生成接口访问令牌 Token
* *
* @param USERNAME
* @param PASSWORD
* @return * @return
*/ */
private String getToken(String USERNAME, String PASSWORD) { private String getToken(SysUser user) {
String token = JwtUtil.sign(USERNAME, PASSWORD); // 使用封装方法:一步完成登录和设置用户信息
redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token); LoginUser loginUser = new LoginUser();
redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, 60); BeanUtils.copyProperties(user, loginUser);
return token; return LoginUserUtils.doLogin(loginUser);
} }

View File

@ -1,5 +1,6 @@
package org.jeecg.modules.system.controller; package org.jeecg.modules.system.controller;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.aliyuncs.exceptions.ClientException; import com.aliyuncs.exceptions.ClientException;
@ -8,8 +9,9 @@ import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import io.swagger.v3.oas.annotations.tags.Tag; import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.SecurityUtils; import org.apache.tomcat.util.threads.ThreadPoolExecutor;
import org.apache.shiro.authz.annotation.RequiresRoles; import org.jeecg.common.util.LoginUserUtils;
import cn.dev33.satoken.annotation.SaCheckRole;
import org.jeecg.common.api.vo.Result; import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CacheConstant; import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.constant.CommonConstant; import org.jeecg.common.constant.CommonConstant;
@ -23,7 +25,6 @@ import org.jeecg.config.JeecgBaseConfig;
import org.jeecg.modules.base.service.BaseCommonService; import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.modules.system.entity.SysDepart; import org.jeecg.modules.system.entity.SysDepart;
import org.jeecg.modules.system.entity.SysRoleIndex; import org.jeecg.modules.system.entity.SysRoleIndex;
import org.jeecg.modules.system.entity.SysTenant;
import org.jeecg.modules.system.entity.SysUser; import org.jeecg.modules.system.entity.SysUser;
import org.jeecg.modules.system.model.SysLoginModel; import org.jeecg.modules.system.model.SysLoginModel;
import org.jeecg.modules.system.service.*; import org.jeecg.modules.system.service.*;
@ -31,7 +32,6 @@ import org.jeecg.modules.system.service.impl.SysBaseApiImpl;
import org.jeecg.modules.system.util.RandImageUtil; import org.jeecg.modules.system.util.RandImageUtil;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
@ -42,7 +42,6 @@ import java.util.*;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.SynchronousQueue; import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/** /**
* @Author scott * @Author scott
@ -75,7 +74,7 @@ public class LoginController {
/** /**
* 线程池用于异步发送纪要 * 线程池用于异步发送纪要
*/ */
public static ExecutorService cachedThreadPool = new ShiroThreadPoolExecutor(0, 1024, 60L, TimeUnit.SECONDS, new SynchronousQueue<>()); public static ExecutorService cachedThreadPool = new ThreadPoolExecutor(0, 1024, 60L, TimeUnit.SECONDS, new SynchronousQueue<>());
@Operation(summary="登录接口") @Operation(summary="登录接口")
@RequestMapping(value = "/login", method = RequestMethod.POST) @RequestMapping(value = "/login", method = RequestMethod.POST)
@ -149,7 +148,8 @@ public class LoginController {
public Result<JSONObject> getUserInfo(HttpServletRequest request){ public Result<JSONObject> getUserInfo(HttpServletRequest request){
long start = System.currentTimeMillis(); long start = System.currentTimeMillis();
Result<JSONObject> result = new Result<JSONObject>(); Result<JSONObject> result = new Result<JSONObject>();
String username = JwtUtil.getUserNameByToken(request); // 使用Sa-Token获取登录用户名loginId现在是username
String username = StpUtil.getLoginIdAsString();
if(oConvertUtils.isNotEmpty(username)) { if(oConvertUtils.isNotEmpty(username)) {
// 根据用户名查询用户信息 // 根据用户名查询用户信息
SysUser sysUser = sysUserService.getUserByName(username); SysUser sysUser = sysUserService.getUserByName(username);
@ -200,7 +200,8 @@ public class LoginController {
LoginUser sysUser = sysBaseApi.getUserByName(username); LoginUser sysUser = sysBaseApi.getUserByName(username);
if(sysUser!=null) { if(sysUser!=null) {
asyncClearLogoutCache(token, sysUser); // 异步清理 asyncClearLogoutCache(token, sysUser); // 异步清理
SecurityUtils.getSubject().logout(); // 使用Sa-Token退出登录
StpUtil.logout();
return Result.ok("退出登录成功!"); return Result.ok("退出登录成功!");
}else { }else {
return Result.error("Token无效!"); return Result.error("Token无效!");
@ -208,17 +209,13 @@ public class LoginController {
} }
/** /**
* 清理用户缓存 * 清理用户缓存使用Sa-Token
* *
* @param token * @param token
* @param sysUser * @param sysUser
*/ */
private void asyncClearLogoutCache(String token, LoginUser sysUser) { private void asyncClearLogoutCache(String token, LoginUser sysUser) {
cachedThreadPool.execute(()->{ cachedThreadPool.execute(()->{
//清空用户登录Token缓存
redisUtil.del(CommonConstant.PREFIX_USER_TOKEN + token);
//清空用户登录Shiro权限缓存
redisUtil.del(CommonConstant.PREFIX_USER_SHIRO_CACHE + sysUser.getId());
//清空用户的缓存信息包括部门信息例如sys:cache:user::<username> //清空用户的缓存信息包括部门信息例如sys:cache:user::<username>
redisUtil.del(String.format("%s::%s", CacheConstant.SYS_USERS_CACHE, sysUser.getUsername())); redisUtil.del(String.format("%s::%s", CacheConstant.SYS_USERS_CACHE, sysUser.getUsername()));
baseCommonService.addLog("用户名: "+sysUser.getRealname()+",退出成功!", CommonConstant.LOG_TYPE_1, null, sysUser); baseCommonService.addLog("用户名: "+sysUser.getRealname()+",退出成功!", CommonConstant.LOG_TYPE_1, null, sysUser);
@ -290,7 +287,7 @@ public class LoginController {
Result<JSONObject> result = new Result<JSONObject>(); Result<JSONObject> result = new Result<JSONObject>();
String username = user.getUsername(); String username = user.getUsername();
if(oConvertUtils.isEmpty(username)) { if(oConvertUtils.isEmpty(username)) {
LoginUser sysUser = (LoginUser)SecurityUtils.getSubject().getPrincipal(); LoginUser sysUser = LoginUserUtils.getSessionUser();
username = sysUser.getUsername(); username = sysUser.getUsername();
} }
@ -478,15 +475,13 @@ public class LoginController {
*/ */
private Result<JSONObject> userInfo(SysUser sysUser, Result<JSONObject> result, HttpServletRequest request) { private Result<JSONObject> userInfo(SysUser sysUser, Result<JSONObject> result, HttpServletRequest request) {
String username = sysUser.getUsername(); String username = sysUser.getUsername();
String syspassword = sysUser.getPassword();
// 获取用户部门信息 // 获取用户部门信息
JSONObject obj = new JSONObject(new LinkedHashMap<>()); JSONObject obj = new JSONObject(new LinkedHashMap<>());
//1.生成token //1.使用sa-token生成token使用username作为loginId将用户信息存入session
String token = JwtUtil.sign(username, syspassword); LoginUser loginUser = new LoginUser();
// 设置token缓存有效时间 BeanUtils.copyProperties(sysUser, loginUser);
redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token); String token = LoginUserUtils.doLogin(loginUser);
redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000);
obj.put("token", token); obj.put("token", token);
//2.设置登录租户 //2.设置登录租户
@ -584,7 +579,7 @@ public class LoginController {
/** /**
* 切换菜单表为vue3的表 * 切换菜单表为vue3的表
*/ */
@RequiresRoles({"admin"}) @SaCheckRole({"admin"})
@GetMapping(value = "/switchVue3Menu") @GetMapping(value = "/switchVue3Menu")
public Result<String> switchVue3Menu(HttpServletResponse response) { public Result<String> switchVue3Menu(HttpServletResponse response) {
Result<String> res = new Result<String>(); Result<String> res = new Result<String>();
@ -656,11 +651,11 @@ public class LoginController {
//5. 设置登录用户信息 //5. 设置登录用户信息
obj.put("userInfo", sysUser); obj.put("userInfo", sysUser);
//6. 生成token //6. 使用Sa-Token生成token使用username作为loginId、将用户信息存入session
String token = JwtUtil.sign(username, syspassword); LoginUser loginUser = new LoginUser();
// 设置超时时间 BeanUtils.copyProperties(sysUser, loginUser);
redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token); String token = LoginUserUtils.doLogin(loginUser);
redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME*2 / 1000); log.info("App登录成功用户名{}token={}", username, token);
//token 信息 //token 信息
obj.put("token", token); obj.put("token", token);
@ -792,7 +787,7 @@ public class LoginController {
result.setSuccess(false); result.setSuccess(false);
return result; return result;
} }
LoginUser sysUser = (LoginUser) SecurityUtils.getSubject().getPrincipal(); LoginUser sysUser = LoginUserUtils.getSessionUser();
String username = sysUser.getUsername(); String username = sysUser.getUsername();
LambdaQueryWrapper<SysUser> query = new LambdaQueryWrapper<>(); LambdaQueryWrapper<SysUser> query = new LambdaQueryWrapper<>();
query.eq(SysUser::getUsername, username).eq(SysUser::getPhone, mobile); query.eq(SysUser::getUsername, username).eq(SysUser::getPhone, mobile);

View File

@ -1,28 +1,23 @@
package org.jeecg.modules.system.controller; package org.jeecg.modules.system.controller;
import cn.dev33.satoken.session.SaSession;
import cn.dev33.satoken.stp.StpUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.jeecg.common.api.vo.Result; import org.jeecg.common.api.vo.Result;
import org.jeecg.common.constant.CacheConstant; import org.jeecg.common.constant.CacheConstant;
import org.jeecg.common.constant.CommonConstant; import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser; import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.RedisUtil; import org.jeecg.common.util.RedisUtil;
import org.jeecg.common.util.oConvertUtils; import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.base.service.BaseCommonService; import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.modules.system.service.ISysUserService;
import org.jeecg.modules.system.service.impl.SysBaseApiImpl;
import org.jeecg.modules.system.vo.SysUserOnlineVO; import org.jeecg.modules.system.vo.SysUserOnlineVO;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
@ -39,43 +34,58 @@ public class SysUserOnlineController {
@Autowired @Autowired
private RedisUtil redisUtil; private RedisUtil redisUtil;
@Autowired
public RedisTemplate redisTemplate;
@Autowired
public ISysUserService userService;
@Autowired
private SysBaseApiImpl sysBaseApi;
@Resource @Resource
private BaseCommonService baseCommonService; private BaseCommonService baseCommonService;
/**
* 获取在线用户列表使用Sa-Token
*/
@RequestMapping(value = "/list", method = RequestMethod.GET) @RequestMapping(value = "/list", method = RequestMethod.GET)
public Result<Page<SysUserOnlineVO>> list(@RequestParam(name="username", required=false) String username, public Result<Page<SysUserOnlineVO>> list(@RequestParam(name="username", required=false) String username,
@RequestParam(name="pageNo", defaultValue="1") Integer pageNo,@RequestParam(name="pageSize", defaultValue="10") Integer pageSize) { @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
Collection<String> keys = redisUtil.scan(CommonConstant.PREFIX_USER_TOKEN + "*"); @RequestParam(name="pageSize", defaultValue="10") Integer pageSize) {
List<SysUserOnlineVO> onlineList = new ArrayList<SysUserOnlineVO>(); List<SysUserOnlineVO> onlineList = new ArrayList<>();
for (String key : keys) {
String token = (String)redisUtil.get(key); try {
if (StringUtils.isNotEmpty(token)) { // 使用Sa-Token获取所有在线用户的session ID列表
SysUserOnlineVO online = new SysUserOnlineVO(); List<String> sessionIdList = StpUtil.searchSessionId("", 0, -1, false);
online.setToken(token);
//TODO 改成一次性查询 for (String sessionId : sessionIdList) {
LoginUser loginUser = sysBaseApi.getUserByName(JwtUtil.getUsername(token)); try {
if (loginUser != null && !"_reserve_user_external".equals(loginUser.getUsername())) { // 获取session
//update-begin---author:wangshuai ---date:20220104 for[JTC-382]在线用户查询无效------------ SaSession session = StpUtil.getSessionBySessionId(sessionId);
//验证用户名是否与传过来的用户名相同 if (session == null) {
boolean isMatchUsername=true; continue;
//判断用户名是否为空并且当前循环的用户不包含传过来的用户名那么就设成false
if(oConvertUtils.isNotEmpty(username) && !loginUser.getUsername().contains(username)){
isMatchUsername = false;
} }
if(isMatchUsername){
// 从session中获取用户信息
LoginUser loginUser = (LoginUser) session.get("loginUser");
if (loginUser != null && !"_reserve_user_external".equals(loginUser.getUsername())) {
// 用户名筛选
if (oConvertUtils.isEmpty(username) || loginUser.getUsername().contains(username)) {
SysUserOnlineVO online = new SysUserOnlineVO();
BeanUtils.copyProperties(loginUser, online); BeanUtils.copyProperties(loginUser, online);
// 获取该用户的tokenloginId现在是username
try {
String token = StpUtil.getTokenValueByLoginId(loginUser.getUsername());
online.setToken(token);
} catch (Exception e) {
log.debug("获取用户token失败: {}", e.getMessage());
}
onlineList.add(online); onlineList.add(online);
} }
//update-end---author:wangshuai ---date:20220104 for[JTC-382]在线用户查询无效------------ }
} catch (Exception e) {
// 旧的Session数据可能导致反序列化失败记录debug级别日志即可
log.debug("获取session失败可能是旧数据: {}", e.getMessage());
} }
} }
} catch (Exception e) {
log.error("获取在线用户列表失败: {}", e.getMessage(), e);
} }
Collections.reverse(onlineList); Collections.reverse(onlineList);
Page<SysUserOnlineVO> page = new Page<SysUserOnlineVO>(pageNo, pageSize); Page<SysUserOnlineVO> page = new Page<SysUserOnlineVO>(pageNo, pageSize);
@ -100,30 +110,33 @@ public class SysUserOnlineController {
} }
/** /**
* 强退用户 * 强退用户使用Sa-Token
*/ */
@RequestMapping(value = "/forceLogout",method = RequestMethod.POST) @RequestMapping(value = "/forceLogout",method = RequestMethod.POST)
public Result<Object> forceLogout(@RequestBody SysUserOnlineVO online) { public Result<Object> forceLogout(@RequestBody SysUserOnlineVO online) {
//用户退出逻辑 try {
// 验证参数
if (oConvertUtils.isEmpty(online.getToken())) { if (oConvertUtils.isEmpty(online.getToken())) {
return Result.error("退出登录失败"); return Result.error("Token不能为空");
} }
String username = JwtUtil.getUsername(online.getToken());
LoginUser sysUser = sysBaseApi.getUserByName(username); // 使用Sa-Token通过token强制退出登录
if(sysUser!=null) { StpUtil.logoutByTokenValue(online.getToken());
baseCommonService.addLog("强制: "+sysUser.getRealname()+"退出成功!", CommonConstant.LOG_TYPE_1, null,sysUser);
log.info(" 强制 "+sysUser.getRealname()+"退出成功! "); // 清空用户的缓存信息(如果有用户名)
//清空用户登录Token缓存 if (oConvertUtils.isNotEmpty(online.getUsername())) {
redisUtil.del(CommonConstant.PREFIX_USER_TOKEN + online.getToken()); redisUtil.del(String.format("%s::%s", CacheConstant.SYS_USERS_CACHE, online.getUsername()));
//清空用户登录Shiro权限缓存 }
redisUtil.del(CommonConstant.PREFIX_USER_SHIRO_CACHE + sysUser.getId());
//清空用户的缓存信息包括部门信息例如sys:cache:user::<username> // 记录日志
redisUtil.del(String.format("%s::%s", CacheConstant.SYS_USERS_CACHE, sysUser.getUsername())); String username = oConvertUtils.isNotEmpty(online.getUsername()) ? online.getUsername() : "未知用户";
//调用shiro的logout baseCommonService.addLog("强制: " + username + " 退出成功!", CommonConstant.LOG_TYPE_1, null);
SecurityUtils.getSubject().logout(); log.info("强制 {} 退出成功!", username);
return Result.ok("退出登录成功!"); return Result.ok("退出登录成功!");
}else { } catch (Exception e) {
return Result.error("Token无效!"); log.error("强制退出失败: {}", e.getMessage(), e);
return Result.error("退出登录失败:" + e.getMessage());
} }
} }
} }

View File

@ -17,7 +17,9 @@ import org.jeecg.common.constant.CommonConstant;
import org.jeecg.common.constant.enums.MessageTypeEnum; import org.jeecg.common.constant.enums.MessageTypeEnum;
import org.jeecg.common.system.api.ISysBaseAPI; import org.jeecg.common.system.api.ISysBaseAPI;
import org.jeecg.common.system.util.JwtUtil; import org.jeecg.common.system.util.JwtUtil;
import org.jeecg.common.system.vo.LoginUser;
import org.jeecg.common.util.*; import org.jeecg.common.util.*;
import org.springframework.beans.BeanUtils;
import org.jeecg.modules.base.service.BaseCommonService; import org.jeecg.modules.base.service.BaseCommonService;
import org.jeecg.modules.system.entity.SysDepart; import org.jeecg.modules.system.entity.SysDepart;
import org.jeecg.modules.system.entity.SysThirdAccount; import org.jeecg.modules.system.entity.SysThirdAccount;
@ -211,12 +213,10 @@ public class ThirdLoginController {
} }
private String saveToken(SysUser user) { private String saveToken(SysUser user) {
// 生成token // 使用封装方法:一步完成登录和设置用户信息
String token = JwtUtil.sign(user.getUsername(), user.getPassword()); LoginUser loginUser = new LoginUser();
redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token); BeanUtils.copyProperties(user, loginUser);
// 设置超时时间 return LoginUserUtils.doLogin(loginUser);
redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME * 2 / 1000);
return token;
} }
/** /**