/** * Copyright © 2015-2020 JeePlus All rights reserved. */ package com.jeeplus.common.security.shiro.session; import java.io.Serializable; import java.util.Collection; import java.util.Date; import java.util.Map; import java.util.Set; import javax.servlet.http.HttpServletRequest; import org.apache.shiro.session.Session; import org.apache.shiro.session.UnknownSessionException; import org.apache.shiro.session.mgt.SimpleSession; import org.apache.shiro.session.mgt.eis.AbstractSessionDAO; import org.apache.shiro.subject.PrincipalCollection; import org.apache.shiro.subject.support.DefaultSubjectContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import redis.clients.jedis.Jedis; import com.google.common.collect.Sets; import com.jeeplus.common.config.Global; import com.jeeplus.common.utils.DateUtils; import com.jeeplus.common.utils.JedisUtils; import com.jeeplus.common.utils.StringUtils; import com.jeeplus.common.web.Servlets; /** * 自定义授权会话管理类 * @author jeeplus * @version 2014-7-20 */ public class JedisSessionDAO extends AbstractSessionDAO implements SessionDAO { private Logger logger = LoggerFactory.getLogger(getClass()); private String sessionKeyPrefix = "shiro_session_"; @Override public void update(Session session) throws UnknownSessionException { if (session == null || session.getId() == null) { return; } HttpServletRequest request = Servlets.getRequest(); if (request != null){ String uri = request.getServletPath(); // 如果是静态文件,则不更新SESSION if (Servlets.isStaticFile(uri)){ return; } // 如果是视图文件,则不更新SESSION if (StringUtils.startsWith(uri, Global.getConfig("web.view.prefix")) && StringUtils.endsWith(uri, Global.getConfig("web.view.suffix"))){ return; } // 手动控制不更新SESSION if (Global.NO.equals(request.getParameter("updateSession"))){ return; } } Jedis jedis = null; try { jedis = JedisUtils.getResource(); // 获取登录者编号 PrincipalCollection pc = (PrincipalCollection)session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY); String principalId = pc != null ? pc.getPrimaryPrincipal().toString() : StringUtils.EMPTY; jedis.hset(sessionKeyPrefix, session.getId().toString(), principalId + "|" + session.getTimeout() + "|" + session.getLastAccessTime().getTime()); jedis.set(JedisUtils.getBytesKey(sessionKeyPrefix + session.getId()), JedisUtils.toBytes(session)); // 设置超期时间 int timeoutSeconds = (int)(session.getTimeout() / 1000); jedis.expire((sessionKeyPrefix + session.getId()), timeoutSeconds); logger.debug("update {} {}", session.getId(), request != null ? request.getRequestURI() : ""); } catch (Exception e) { logger.error("update {} {}", session.getId(), request != null ? request.getRequestURI() : "", e); } finally { JedisUtils.returnResource(jedis); } } @Override public void delete(Session session) { if (session == null || session.getId() == null) { return; } Jedis jedis = null; try { jedis = JedisUtils.getResource(); jedis.hdel(JedisUtils.getBytesKey(sessionKeyPrefix), JedisUtils.getBytesKey(session.getId().toString())); jedis.del(JedisUtils.getBytesKey(sessionKeyPrefix + session.getId())); logger.debug("delete {} ", session.getId()); } catch (Exception e) { logger.error("delete {} ", session.getId(), e); } finally { JedisUtils.returnResource(jedis); } } @Override public Collection getActiveSessions() { return getActiveSessions(true); } /** * 获取活动会话 * @param includeLeave 是否包括离线(最后访问时间大于3分钟为离线会话) * @return */ @Override public Collection getActiveSessions(boolean includeLeave) { return getActiveSessions(includeLeave, null, null); } /** * 获取活动会话 * @param includeLeave 是否包括离线(最后访问时间大于3分钟为离线会话) * @param principal 根据登录者对象获取活动会话 * @param filterSession 不为空,则过滤掉(不包含)这个会话。 * @return */ @Override public Collection getActiveSessions(boolean includeLeave, Object principal, Session filterSession){ Set sessions = Sets.newHashSet(); Jedis jedis = null; try { jedis = JedisUtils.getResource(); Map map = jedis.hgetAll(sessionKeyPrefix); for (Map.Entry e : map.entrySet()){ if (StringUtils.isNotBlank(e.getKey()) && StringUtils.isNotBlank(e.getValue())){ String[] ss = StringUtils.split(e.getValue(), "|"); if (ss != null && ss.length == 3){// jedis.exists(sessionKeyPrefix + e.getKey())){ // Session session = (Session)JedisUtils.toObject(jedis.get(JedisUtils.getBytesKey(sessionKeyPrefix + e.getKey()))); SimpleSession session = new SimpleSession(); session.setId(e.getKey()); session.setAttribute("principalId", ss[0]); session.setTimeout(Long.valueOf(ss[1])); session.setLastAccessTime(new Date(Long.valueOf(ss[2]))); try{ // 验证SESSION session.validate(); boolean isActiveSession = false; // 不包括离线并符合最后访问时间小于等于3分钟条件。 if (includeLeave || DateUtils.pastMinutes(session.getLastAccessTime()) <= 3){ isActiveSession = true; } // 符合登陆者条件。 if (principal != null){ PrincipalCollection pc = (PrincipalCollection)session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY); if (principal.toString().equals(pc != null ? pc.getPrimaryPrincipal().toString() : StringUtils.EMPTY)){ isActiveSession = true; } } // 过滤掉的SESSION if (filterSession != null && filterSession.getId().equals(session.getId())){ isActiveSession = false; } if (isActiveSession){ sessions.add(session); } } // SESSION验证失败 catch (Exception e2) { jedis.hdel(sessionKeyPrefix, e.getKey()); } } // 存储的SESSION不符合规则 else{ jedis.hdel(sessionKeyPrefix, e.getKey()); } } // 存储的SESSION无Value else if (StringUtils.isNotBlank(e.getKey())){ jedis.hdel(sessionKeyPrefix, e.getKey()); } } logger.info("getActiveSessions size: {} ", sessions.size()); } catch (Exception e) { logger.error("getActiveSessions", e); } finally { JedisUtils.returnResource(jedis); } return sessions; } @Override protected Serializable doCreate(Session session) { HttpServletRequest request = Servlets.getRequest(); if (request != null){ String uri = request.getServletPath(); // 如果是静态文件,则不创建SESSION if (Servlets.isStaticFile(uri)){ return null; } } Serializable sessionId = this.generateSessionId(session); this.assignSessionId(session, sessionId); this.update(session); return sessionId; } @Override protected Session doReadSession(Serializable sessionId) { Session s = null; HttpServletRequest request = Servlets.getRequest(); if (request != null){ String uri = request.getServletPath(); // 如果是静态文件,则不获取SESSION if (Servlets.isStaticFile(uri)){ return null; } s = (Session)request.getAttribute("session_"+sessionId); } if (s != null){ return s; } Session session = null; Jedis jedis = null; try { jedis = JedisUtils.getResource(); // if (jedis.exists(sessionKeyPrefix + sessionId)){ session = (Session)JedisUtils.toObject(jedis.get( JedisUtils.getBytesKey(sessionKeyPrefix + sessionId))); // } logger.debug("doReadSession {} {}", sessionId, request != null ? request.getRequestURI() : ""); } catch (Exception e) { logger.error("doReadSession {} {}", sessionId, request != null ? request.getRequestURI() : "", e); } finally { JedisUtils.returnResource(jedis); } if (request != null && session != null){ request.setAttribute("session_"+sessionId, session); } return session; } @Override public Session readSession(Serializable sessionId) throws UnknownSessionException { try{ return super.readSession(sessionId); }catch (UnknownSessionException e) { return null; } } public String getSessionKeyPrefix() { return sessionKeyPrefix; } public void setSessionKeyPrefix(String sessionKeyPrefix) { this.sessionKeyPrefix = sessionKeyPrefix; } }