用redis实现会话共享

    在北京项目中遇到了session不能共享的问题,按照一般的处理方式,Nginx配置ip_hash即可,但是配置之后也没用。仔细分析北京的环境,请求的地址是外网四层地址,再用Nginx转发到内网四层地址,所以即使在nginx配置了ipHash,也会在四层交换被打乱。最后采用的解决方案是将session写入redis,因为北京项目使用了shiro,自定义授权会话管理即可

 

1.spring-context-shiro.xml中配置路径

 

<bean id="sessionDAO" class="com.cs.core.common.security.shiro.session.JedisSessionDAO">

<property name="sessionIdGenerator" ref="idGen" />

<property name="sessionKeyPrefix" value="jcs_session_" />

</bean>

2.JedisSessionDao.java

 

package com.cs.core.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.annotation.Resource;

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 com.ailk.jike.common.cache.redis.RedisClient;

import com.cs.core.common.config.Global;

import com.cs.core.common.utils.DateUtils;

import com.cs.core.common.web.Servlets;

import com.google.common.collect.Sets;

 

/**

 * 自定义授权会话管理类

 */

public class JedisSessionDAO extends AbstractSessionDAO implements SessionDAO {

 

private Logger logger = LoggerFactory.getLogger(getClass());

 

private String sessionKeyPrefix = "jcs_session_";

 

@Resource

private RedisClient redisClient;

 

 

@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 (org.apache.commons.lang3.StringUtils.startsWith(uri, Global.getConfig("web.view.prefix"))

&& org.apache.commons.lang3.StringUtils.endsWith(uri, Global.getConfig("web.view.suffix"))){

return;

}

// 手动控制不更新SESSION

if (Global.NO.equals(request.getParameter("updateSession"))){

return;

}

}

 

try {

 

 

// 获取登录者编号

PrincipalCollection pc = (PrincipalCollection)session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);

String principalId = pc != null ? pc.getPrimaryPrincipal().toString() : org.apache.commons.lang3.StringUtils.EMPTY;

 

redisClient.hset(sessionKeyPrefix, session.getId().toString(), principalId + "|" + session.getTimeout() + "|" + session.getLastAccessTime().getTime());

redisClient.set(sessionKeyPrefix + session.getId(), session);

 

// 设置超期时间

long timeoutSeconds = (long)(session.getTimeout() / 1000);

redisClient.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);

}

}

 

@Override

public void delete(Session session) {

if (session == null || session.getId() == null) {

return;

}

 

//Jedis jedis = null;

try {

//jedis = JedisUtils.getResource();

 

redisClient.hdel(sessionKeyPrefix, session.getId().toString());

redisClient.del(sessionKeyPrefix+ session.getId());

 

logger.debug("delete {} ", session.getId());

} catch (Exception e) {

logger.error("delete {} ", session.getId(), e);

}

}

 

@Override

public Collection<Session> getActiveSessions() {

return getActiveSessions(true);

}

 

/**

 * 获取活动会话

 * @param includeLeave 是否包括离线(最后访问时间大于3分钟为离线会话)

 * @return

 */

@Override

public Collection<Session> getActiveSessions(boolean includeLeave) {

return getActiveSessions(includeLeave, null, null);

}

 

/**

 * 获取活动会话

 * @param includeLeave 是否包括离线(最后访问时间大于3分钟为离线会话)

 * @param principal 根据登录者对象获取活动会话

 * @param filterSession 不为空,则过滤掉(不包含)这个会话。

 * @return

 */

@Override

public Collection<Session> getActiveSessions(boolean includeLeave, Object principal, Session filterSession){

Set<Session> sessions = Sets.newHashSet();

 

//Jedis jedis = null;

try {

//jedis = JedisUtils.getResource();

Map<String, String> map = redisClient.hgetAll(sessionKeyPrefix);

for (Map.Entry<String, String> e : map.entrySet()){

if (org.apache.commons.lang3.StringUtils.isNotBlank(e.getKey()) && org.apache.commons.lang3.StringUtils.isNotBlank(e.getValue())){

 

String[] ss = org.apache.commons.lang3.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() : org.apache.commons.lang3.StringUtils.EMPTY)){

isActiveSession = true;

}

}

// 过滤掉的SESSION

if (filterSession != null && filterSession.getId().equals(session.getId())){

isActiveSession = false;

}

if (isActiveSession){

sessions.add(session);

}

 

}

// SESSION验证失败

catch (Exception e2) {

    redisClient.hdel(sessionKeyPrefix, e.getKey());

}

}

// 存储的SESSION不符合规则

else{

    redisClient.hdel(sessionKeyPrefix, e.getKey());

}

}

// 存储的SESSIONValue

else if (org.apache.commons.lang3.StringUtils.isNotBlank(e.getKey())){

    redisClient.hdel(sessionKeyPrefix, e.getKey());

}

}

logger.info("getActiveSessions size: {} ", sessions.size());

} catch (Exception e) {

logger.error("getActiveSessions", e);

}

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;

try {

session = (Session)redisClient.get(sessionKeyPrefix + sessionId);

logger.debug("doReadSession {} {}", sessionId, request != null ? request.getRequestURI() : "");

} catch (Exception e) {

logger.error("doReadSession {} {}", sessionId, request != null ? request.getRequestURI() : "", e);

}

 

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;

}

 

}

 

posted @ 2017-06-05 11:14  六月飞鸟  阅读(3610)  评论(0编辑  收藏  举报