``查阅网上的各种办法都没解决 就研究了一下代码
@Override
public boolean onAccessDenied(ServletRequest request, ServletResponse response)throws Exception {
Subject subject = getSubject(request,response);
// 没有登录授权 且没有记住我
if(!subject.isAuthenticated() && !subject.isRemembered()){
// 如果没有登录,直接进行之后的流程,如果是登录则 终止后续的
return true;
}
// 获得用户请求的URI
HttpServletRequest req=(HttpServletRequest) request;
String path = req.getRequestURI();
logger.info("===当前请求的uri:" + path);
Session session = subject.getSession();
***if(path.equals("/login/login")||path.equals("/stamp/selectCount")||path.equals("/contract/selectCount")||path.equals("/WarningInfo/selectCount")||path.equals("/message/getList")){
return true;
}***
logger.info("session时间设置:" + String.valueOf(session.getTimeout()));
try{
// 当前用户
UserInfo user = (UserInfo) subject.getPrincipal();
String username = user.getLoginName();
logger.info("===当前用户username:" + username);
Serializable sessionId = session.getId();
logger.info("===当前用户sessionId:" + sessionId);
// 读取缓存用户 没有就存入
Deque<Serializable> deque = cache.get(username);
logger.info("===当前deque:" + deque);
if (deque == null) {
// 初始化队列
deque = new ArrayDeque<Serializable>();
logger.info("deque初始化:" + deque);
}
// 如果队列里没有此sessionId,且用户没有被踢出;放入队列
if (!deque.contains(sessionId) && (Boolean)session.getAttribute("kickout") == false) {
// 将sessionId存入队列
deque.push(sessionId);
// 将用户的sessionId队列缓存
cache.put(username, deque);
logger.info("deque push:" + deque);
}
// 如果队列里的sessionId数超出最大会话数,开始踢人
while (deque.size() > maxSession) {
logger.info("===deque队列长度:" + deque.size());
Serializable kickoutSessionId = null;
// 是否踢出后来登录的,默认是false;即后者登录的用户踢出前者登录的用户;
if (kickoutAfter) { // 如果踢出后者
System.out.println("踢出后者");
kickoutSessionId = deque.removeFirst();
} else { // 否则踢出前者
System.out.println("踢出前者");
kickoutSessionId = deque.removeLast();
}
// 踢出后再更新下缓存队列
cache.put(username, deque);
try{
// 获取被踢出的sessionId的session对象
Session kickoutSession = sessionManager
.getSession(new DefaultSessionKey(kickoutSessionId));
if (kickoutSession != null) {
kickoutSession.setAttribute("kickout", true);
}
}catch (Exception e){
}
}
// 如果被踢出了,(前者或后者)直接退出,重定向到踢出后的地址
if (deque.size()>0 && (Boolean) session.getAttribute("kickout") != null
&& (Boolean) session.getAttribute("kickout") == true){
// 会话被踢出了
try {
// 退出登录
System.out.println("被踢了!!"+subject.getSession().getId());
subject.logout();
} catch (Exception e) { // ignore
}
saveRequest(request);
logger.info("===踢出后用户重定向的路径kickoutUrl:" + kickoutUrl);
return isAjaxResponse(request,response);
}
return true;
}catch (Exception e){
logger.error("控制用户在线数量【KickoutSessionFilter.onAccessDenied】异常!", e);
return false;
}
}
因为新用户登录该系统,会同时调多个接口,每个接口都执行一次onAccessDenied 这样并发执行会导致多踢了用户的现象。所以我加入了筛选判断,把登录后首页调用的接口数目保持为1即可。
if(path.equals(“/login/login”)||path.equals(“/stamp/selectCount”)||path.equals(“/contract/selectCount”)||path.equals(“/WarningInfo/selectCount”)||path.equals(“/message/getList”)){
return true;
}