版权声明:转载请附链接 https://blog.csdn.net/qq_23536449/article/details/89916049
实现思路
1.一个类,类中维护着一个已登录用户的map,每次登录取出上次该用户对应的session;并给session添加一个过期的属性标识lastHttpSession.setAttribute(BE_KICKED,"您的账号在另一地点登录,您被迫下线")
2.写一个sessionFilter,该sessionFilter取出每个request请求实例中维护的session,判断session中有没有BE_KICKEd
3.如果存在说明该session是被踢掉用户,返回给客户端被踢信息
废话不多说直接上代码
UserStatistiUtil
package com.gysoft.sso.utils;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import javax.servlet.http.HttpSession;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
/**
* @author 周宁
* @Date 2018-06-13 20:14
*/
public class UserStatisticUtil {
/**
* 默认缓存2个小时
*/
public static final Integer DEFAULT_CACHE_SECONDS = 60*60*2;
/**
* 缓存容器的默认大小
*/
private static final Integer DEFAULT_SIZE = 10000;
/**
* 存放用户对应Session的map,用于踢出用户
*/
public static ConcurrentHashMap<String,HttpSession> userSessionMap = new ConcurrentHashMap();
/**
* 缓存容器,存放被踢下线的SessionId,如果一个被踢用户过了2小时去请求那么就是session超时而不是被踢
*/
private static final Cache<String, HttpSession> invalidSessionIdMap = CacheBuilder.newBuilder().maximumSize(DEFAULT_SIZE)
.expireAfterWrite(DEFAULT_CACHE_SECONDS, TimeUnit.SECONDS).build();
/**
* 判断是否是过期的sessionId
* @param sessionId
* @return
*/
public static boolean isInvalidSessionId(String sessionId){
return getInvalidSessionId(sessionId)!=null;
}
/**
* 取出已经过期的sessionId
* @param key
* @return Object
*/
public static HttpSession getInvalidSessionId(String key) {
return invalidSessionIdMap.getIfPresent(key);
}
/**
* 放入已经过期的sessionId
* @param key
* @param value
*/
public static void putInvalidSessionId(String key, HttpSession value) {
invalidSessionIdMap.put(key, value);
}
}
CustomCas30ProxyReceivingTicketValidationFilter
public class CustomCas30ProxyReceivingTicketValidationFilter extends Cas30ProxyReceivingTicketValidationFilter {
@Override
protected void onSuccessfulValidation(HttpServletRequest request, HttpServletResponse response, Assertion assertion) {
String username =assertion.getPrincipal().getName();
HttpSession lastHttpSession = UserStatisticUtil.userSessionMap.get(username);
if(null!=lastHttpSession&&!UserStatisticUtil.isInvalidSessionId(lastHttpSession.getId())){
try{
lastHttpSession.setAttribute(BE_KICKED,"您的账号在另一地点登录,您被迫下线");
}catch (IllegalStateException e){
//TODO Nothing 出现这种情况的原因是浏览器的session过期了但是未被及时清除
}
}
String dcpLoginInfo = (String) assertion.getPrincipal().getAttributes().get(DCP_LOGIN_INFO);
HttpSession session = request.getSession();
session.setAttribute(DCP_LOGIN_INFO,dcpLoginInfo);
UserStatisticUtil.userSessionMap.put(username,session);
}
}
SessionTimeOutFilter
package com.gysoft.sso.filter;
import com.gysoft.sso.utils.UserStatisticUtil;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import static com.gysoft.sso.bean.SessionVariable.BE_KICKED;
import static com.gysoft.sso.bean.SessionVariable.DCP_LOGIN_INFO;
import static com.gysoft.sso.utils.UserStatisticUtil.DEFAULT_CACHE_SECONDS;
/**
* session超时过滤
* @author 周宁
* @Date 2018-06-12 14:08
*/
public class SessionTimeOutFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest req = (HttpServletRequest) request;
HttpServletResponse res = (HttpServletResponse) response;
HttpSession session = req.getSession();
String queryString = req.getQueryString();
//url地址需要单点认证,且session不存在,则需要验证地址是否包含ticket
if(!CustomAuthenticationFilter.isRequestUrlExcluded(req)&&session.getAttribute(DCP_LOGIN_INFO)==null){
if(queryString==null||queryString.indexOf("ticket")==-1){
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("{\"msg\": \"用户未登录\",\"code\": " + 302 + ",\"result\": "+null+"}");
return;
}
}
//在线互踢
if(session.getAttribute(BE_KICKED)!=null){
UserStatisticUtil.putInvalidSessionId(session.getId(),session,DEFAULT_CACHE_SECONDS);
String msg = (String) session.getAttribute(BE_KICKED);
session.invalidate();
response.setContentType("application/json;charset=utf-8");
response.getWriter().write("{\"msg\": "+msg+",\"code\": " + 302 + ",\"result\": " + null + "}");
return;
}
chain.doFilter(req,res);
}
@Override
public void destroy() {
}
}