Skip to content

Commit

Permalink
Merge branch 'chacky'
Browse files Browse the repository at this point in the history
  • Loading branch information
leechenxiang committed Nov 11, 2017
2 parents d19bdf1 + 315d059 commit 6cab9a8
Show file tree
Hide file tree
Showing 2 changed files with 149 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package com.itzixi.web.shiro.filter;

import java.io.Serializable;
import java.util.Deque;
import java.util.LinkedList;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.DefaultSessionKey;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.apache.shiro.web.util.WebUtils;

import com.itzixi.pojo.ActiveUser;

/**
*
* @Title: KickoutSessionControlFilter.java
* @Package com.agood.bejavagod.controller.filter
* @Description: 同一用户后登陆踢出前面的用户
* Copyright: Copyright (c) 2016
* Company:Nathan.Lee.Salvatore
*
* @author leechenxiang
* @date 2016年12月12日 下午7:25:40
* @version V1.0
*/
public class KickoutSessionControlFilter extends AccessControlFilter {

private String kickoutUrl; //踢出后到的地址
private boolean kickoutAfter = false; //踢出之前登录的/之后登录的用户 默认踢出之前登录的用户
private int maxSession = 1; //同一个帐号最大会话数 默认1

private SessionManager sessionManager;

// TODO 分布式集群环境下,需要改为redis
private Cache<String, Deque<Serializable>> cache;

public void setKickoutUrl(String kickoutUrl) {
this.kickoutUrl = kickoutUrl;
}

public void setKickoutAfter(boolean kickoutAfter) {
this.kickoutAfter = kickoutAfter;
}

public void setMaxSession(int maxSession) {
this.maxSession = maxSession;
}

public void setSessionManager(SessionManager sessionManager) {
this.sessionManager = sessionManager;
}

public void setCacheManager(CacheManager cacheManager) {
this.cache = cacheManager.getCache("shiro-kickout-session");
}

@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
return false;
}

@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
Subject subject = getSubject(request, response);
if(!subject.isAuthenticated() && !subject.isRemembered()) {
//如果没有登录,直接进行之后的流程
return true;
}

Session session = subject.getSession();
ActiveUser user = (ActiveUser)subject.getPrincipal();
String username = user.getUsername();
Serializable sessionId = session.getId();

// 同步控制, 同步在本机的缓存中是有效的,但是一旦放入集群中,就会失效
Deque<Serializable> deque = cache.get(username);
if(deque == null) {
deque = new LinkedList<Serializable>();
cache.put(username, deque);
}

//如果队列里没有此sessionId,且用户没有被踢出;放入队列
if(!deque.contains(sessionId) && session.getAttribute("kickout") == null) {
deque.push(sessionId);
}

//如果队列里的sessionId数超出最大会话数,开始踢人
while(deque.size() > maxSession) {
Serializable kickoutSessionId = null;
if(kickoutAfter) { //如果踢出后者
kickoutSessionId = deque.removeFirst();
} else { //否则踢出前者
kickoutSessionId = deque.removeLast();
}
try {
Session kickoutSession = sessionManager.getSession(new DefaultSessionKey(kickoutSessionId));
if(kickoutSession != null) {
//设置会话的kickout属性表示踢出了
kickoutSession.setAttribute("kickout", true);
}
} catch (Exception e) {//ignore exception
}
}

//如果被踢出了,直接退出,重定向到踢出后的地址
if (session.getAttribute("kickout") != null) {
//会话被踢出了
try {
subject.logout();
} catch (Exception e) { //ignore
}
saveRequest(request);

HttpServletRequest httpRequest = WebUtils.toHttp(request);
if (ShiroFilterUtils.isAjax(httpRequest)) {
HttpServletResponse httpServletResponse = WebUtils.toHttp(response);
httpServletResponse.sendError(ShiroFilterUtils.HTTP_STATUS_SESSION_EXPIRE);
return false;
} else {
WebUtils.issueRedirect(request, response, kickoutUrl);
return false;
}
}

return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
<entry key="authc">
<bean class="com.itzixi.web.shiro.filter.CustomFormAuthenticationFilter"></bean>
</entry>
<entry key="kickout" value-ref="kickoutSessionControlFilter"/>
</map>
</property>

Expand All @@ -92,12 +93,22 @@
/login.action = anon
/regist.action = anon

/** = authc
<!-- authc -->
/** = kickout,authc
<!-- kickout,authc -->
</value>
</property>
</bean>

<bean id="kickoutSessionControlFilter" class="com.itzixi.web.shiro.filter.KickoutSessionControlFilter">
<property name="cacheManager" ref="shiroEhcacheManager"/>
<property name="sessionManager" ref="sessionManager"/>
<!-- 是否踢出后来登录的,默认是false;即后者登录的用户踢出前者登录的用户 -->
<property name="kickoutAfter" value="false"/>
<!-- 同一个用户最大的会话数,默认1;比如2的意思是同一个用户允许最多同时两个人登录 -->
<property name="maxSession" value="1"/>
<property name="kickoutUrl" value="/login.action"/>
</bean>

<!-- 保证实现了Shiro内部lifecycle函数的bean执行 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

Expand Down

0 comments on commit 6cab9a8

Please sign in to comment.