disl 发表于 2017-12-21 14:18:26

用redis实现会话共享

  在北京项目中遇到了session不能共享的问题,按照一般的处理方式,Nginx配置ip_hash即可,但是配置之后也没用。仔细分析北京的环境,请求的地址是外网四层地址,再用Nginx转发到内网四层地址,所以即使在nginx配置了ipHash,也会在四层交换被打乱。最后采用的解决方案是将session写入redis,因为北京项目使用了shiro,自定义授权会话管理即可
  1.在spring-context-shiro.xml中配置路径
  <bean>
  <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>  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);
  session.setTimeout(Long.valueOf(ss));
  session.setLastAccessTime(new Date(Long.valueOf(ss)));
  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());
  }
  }
  // 存储的SESSION无Value
  else if (org.apache.commons.lang3.StringUtils.isNotBlank(e.getKey())){
  redisClient.hdel(sessionKeyPrefix, e.getKey());
  }
  }

  logger.info("getActiveSessions>  } 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;
  }
  }
页: [1]
查看完整版本: 用redis实现会话共享