package com.fzzy.sys.controller.monitor;
|
|
import com.ruoyi.common.annotation.Log;
|
import com.ruoyi.common.constant.ShiroConstants;
|
import com.ruoyi.common.core.controller.BaseController;
|
import com.ruoyi.common.core.domain.AjaxResult;
|
import com.ruoyi.common.core.domain.entity.SysUser;
|
import com.ruoyi.common.core.page.PageDomain;
|
import com.ruoyi.common.core.page.TableDataInfo;
|
import com.ruoyi.common.core.page.TableSupport;
|
import com.ruoyi.common.enums.BusinessType;
|
import com.ruoyi.common.utils.ShiroUtils;
|
import com.ruoyi.common.utils.StringUtils;
|
import com.ruoyi.common.utils.spring.SpringUtils;
|
import com.ruoyi.system.domain.SysUserOnline;
|
import lombok.extern.slf4j.Slf4j;
|
import org.apache.shiro.authz.annotation.Logical;
|
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
import org.apache.shiro.cache.Cache;
|
import org.apache.shiro.session.Session;
|
import org.apache.shiro.subject.SimplePrincipalCollection;
|
import org.apache.shiro.subject.support.DefaultSubjectContext;
|
import org.crazycake.shiro.RedisCacheManager;
|
import org.crazycake.shiro.RedisSessionDAO;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Controller;
|
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.PostMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.ResponseBody;
|
|
import java.io.Serializable;
|
import java.util.*;
|
|
/**
|
* 在线用户监控
|
*
|
* @author ruoyi
|
*/
|
@Slf4j
|
@Controller
|
@RequestMapping("/monitor/online")
|
public class SysUserOnlineController extends BaseController {
|
|
private String prefix = "monitor/online";
|
|
@Autowired
|
private RedisSessionDAO redisSessionDAO;
|
|
@RequiresPermissions("monitor:online:view")
|
@GetMapping()
|
public String online() {
|
return prefix + "/online";
|
}
|
|
@RequiresPermissions("monitor:online:list")
|
@PostMapping("/list")
|
@ResponseBody
|
public TableDataInfo list(SysUserOnline userOnline) {
|
String ipaddr = userOnline.getIpaddr();
|
String loginName = userOnline.getLoginName();
|
TableDataInfo rspData = new TableDataInfo();
|
Collection<Session> sessions = redisSessionDAO.getActiveSessions();
|
Iterator<Session> it = sessions.iterator();
|
List<SysUserOnline> sessionList = new ArrayList<SysUserOnline>();
|
long currentTime = System.currentTimeMillis();
|
while (it.hasNext()) {
|
Session session = it.next();
|
// 检查 Session 是否过期
|
if (isSessionExpired(session, currentTime)) {
|
continue;
|
}
|
|
SysUserOnline user = getSession(session);
|
if (StringUtils.isNotNull(user)) {
|
if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(loginName)) {
|
if (StringUtils.equals(ipaddr, user.getIpaddr())
|
&& StringUtils.equals(loginName, user.getLoginName())) {
|
sessionList.add(user);
|
}
|
} else if (StringUtils.isNotEmpty(ipaddr)) {
|
if (StringUtils.equals(ipaddr, user.getIpaddr())) {
|
sessionList.add(user);
|
}
|
} else if (StringUtils.isNotEmpty(loginName)) {
|
if (StringUtils.equals(loginName, user.getLoginName())) {
|
sessionList.add(user);
|
}
|
} else {
|
sessionList.add(user);
|
}
|
}
|
}
|
// 对 sessionList 根据 lastAccessTime 进行 desc 排序
|
sessionList.sort((a, b) -> {
|
if (a.getLastAccessTime() == null) {
|
return 1;
|
}
|
if (b.getLastAccessTime() == null) {
|
return -1;
|
}
|
return b.getLastAccessTime().compareTo(a.getLastAccessTime());
|
});
|
// 对 sessionList 进行分页
|
PageDomain pageDomain = TableSupport.buildPageRequest();
|
Integer pageNum = pageDomain.getPageNum();
|
Integer pageSize = pageDomain.getPageSize();
|
int total = sessionList.size();
|
int fromIndex = (pageNum - 1) * pageSize;
|
int toIndex = Math.min(fromIndex + pageSize, total);
|
|
if (fromIndex < total) {
|
sessionList = sessionList.subList(fromIndex, toIndex);
|
} else {
|
sessionList = new ArrayList<>();
|
}
|
rspData.setRows(sessionList);
|
rspData.setTotal(total);
|
//返回分页后数据
|
return rspData;
|
}
|
|
/**
|
* 检查 Session 是否已过期
|
*/
|
private boolean isSessionExpired(Session session, long currentTime) {
|
if (session == null) {
|
return true;
|
}
|
|
Long timeout = session.getTimeout();
|
if (timeout == null || timeout <= 0) {
|
timeout = 1800000L; // 默认 30 分钟
|
}
|
|
long lastAccessTime = session.getLastAccessTime().getTime();
|
return (currentTime - lastAccessTime) > timeout;
|
}
|
|
|
@RequiresPermissions(value = {"monitor:online:batchForceLogout", "monitor:online:forceLogout"}, logical = Logical.OR)
|
@Log(title = "在线用户", businessType = BusinessType.FORCE)
|
@PostMapping("/batchForceLogout")
|
@ResponseBody
|
public AjaxResult batchForceLogout(String ids) {
|
if (StringUtils.isBlank(ids)) {
|
return error("参数不能为空");
|
}
|
|
String[] sessionIds = ids.split(",");
|
for (String sessionId : sessionIds) {
|
try {
|
Session session = redisSessionDAO.readSession(sessionId);
|
if (session != null) {
|
if (sessionId.equals(ShiroUtils.getSessionId())) {
|
return error("当前登录用户无法强退");
|
}
|
redisSessionDAO.delete(session);
|
|
Object obj = session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
|
if (obj instanceof SimplePrincipalCollection) {
|
SimplePrincipalCollection spc = (SimplePrincipalCollection) obj;
|
Object principal = spc.getPrimaryPrincipal();
|
if (principal instanceof SysUser) {
|
SysUser sysUser = (SysUser) principal;
|
removeUserCache(sysUser.getLoginName(), sessionId);
|
}
|
}
|
}
|
} catch (Exception e) {
|
log.error("强退用户失败,sessionId: {}", sessionId, e);
|
}
|
}
|
return success();
|
}
|
|
|
private SysUserOnline getSession(Session session) {
|
Object obj = session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
|
if (null == obj) {
|
return null;
|
}
|
if (obj instanceof SimplePrincipalCollection) {
|
SimplePrincipalCollection spc = (SimplePrincipalCollection) obj;
|
obj = spc.getPrimaryPrincipal();
|
if (null != obj && obj instanceof SysUser) {
|
SysUser sysUser = (SysUser) obj;
|
SysUserOnline userOnline = new SysUserOnline();
|
userOnline.setSessionId(session.getId().toString());
|
userOnline.setLoginName(sysUser.getLoginName());
|
if (StringUtils.isNotNull(sysUser.getDept()) && StringUtils.isNotEmpty(sysUser.getDept().getDeptName())) {
|
userOnline.setDeptName(sysUser.getDept().getDeptName());
|
}
|
userOnline.setIpaddr(session.getHost());
|
userOnline.setStartTimestamp(session.getStartTimestamp());
|
userOnline.setLastAccessTime(session.getLastAccessTime());
|
return userOnline;
|
}
|
}
|
return null;
|
}
|
|
public void removeUserCache(String loginName, String sessionId) {
|
Cache<String, Deque<Serializable>> cache = SpringUtils.getBean(RedisCacheManager.class).getCache(ShiroConstants.SYS_USERCACHE);
|
Deque<Serializable> deque = cache.get(loginName);
|
if (StringUtils.isEmpty(deque) || deque.size() == 0) {
|
return;
|
}
|
deque.remove(sessionId);
|
cache.put(loginName, deque);
|
}
|
}
|