鉴于网上很多关于 shiro做集群后 session共享的回答 但是都有问题 我自己实践写一遍记录

第一个是继承 AbstractSessionDAO 这个类 这个类是shiro去保存session的

import com.newcoin.manager.web.utils.ShiroSessionRedisManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

public class SessionRedisDao extends AbstractSessionDAO {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private ShiroSessionRedisManager redisManager;

    /**
     * The Redis key prefix for the sessions
     */
    private static final String KEY_PREFIX = "shiro_redis_session:";

    @Override
    public void update(Session session) throws UnknownSessionException {
        this.saveSession(session);
    }

    @Override
    public void delete(Session session) {
        if (session == null || session.getId() == null) {
            logger.error("session or session id is null");
            return;
        }
        redisManager.del(KEY_PREFIX + session.getId());
    }

    /*@Override
    public Collection<Session> getActiveSessions() {
        Set<Session> sessions = new HashSet<Session>();
        Set<byte[]> keys = redisManager.keys(KEY_PREFIX + "*");
        if(keys != null && keys.size()>0){
            for(byte[] key : keys){
                String deserialize = SerializerUtil.deserialize(key);
                byte[] o = redisManager.get(deserialize);
                Session s = (Session) SerializerUtil.deserialize(o);
                sessions.add(s);
            }
        }
        return sessions;
    }*/

    @Override
    public Collection<Session> getActiveSessions() {
        Set<Session> sessions = new HashSet<Session>();
        Set<byte[]> keys = redisManager.keys(KEY_PREFIX + "*");
        if(keys != null && keys.size()>0){
            for(byte[] key : keys){
//                String deserialize = SerializerUtil.deserialize(key);
                Session o = redisManager.get(new String(key));
//                Session s = (Session) SerializerUtil.deserialize(o.getBytes());
                sessions.add(o);
            }
        }
        return sessions;
    }

    @Override
    protected Serializable doCreate(Session session) {
        Serializable sessionId = this.generateSessionId(session);
        this.assignSessionId(session, sessionId);
        this.saveSession(session);
        return sessionId;
    }

    @Override
    protected Session doReadSession(Serializable sessionId) {
        if(sessionId == null){
            logger.error("session id is null");
            return null;
        }

        Session s = (Session)redisManager.get(KEY_PREFIX + sessionId);
        return s;
    }

    private void saveSession(Session session) throws UnknownSessionException {
        if (session == null || session.getId() == null) {
            logger.error("session or session id is null");
            return;
        }
        //设置过期时间
        long expireTime = 1800000l;
        session.setTimeout(expireTime);
        redisManager.setEx(KEY_PREFIX + session.getId(), session, expireTime);
    }

    public void setRedisManager(ShiroSessionRedisManager redisManager) {
        this.redisManager = redisManager;
    }

    public ShiroSessionRedisManager getRedisManager() {
        return redisManager;
    }
}

以下是2个工具类

import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;

/**
 * 序列化工具类
 * @author HandyZcy
 *
 */
public class SerializerUtil {

    private static final JdkSerializationRedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer();

    /**
     * 序列化对象
     * @param obj
     * @return
     */
    public static <T> byte[] serialize(T obj){
        try {
            return jdkSerializationRedisSerializer.serialize(obj);
        } catch (Exception e) {
            throw new RuntimeException("序列化失败!", e);
        }
    }

    /**
     * 反序列化对象
     * @param bytes 字节数组
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T deserialize(byte[] bytes){
        try {
            return (T) jdkSerializationRedisSerializer.deserialize(bytes);
        } catch (Exception e) {
            throw new RuntimeException("反序列化失败!", e);
        }
    }
}

Redis 工具类 具体的RedisTemplate 自己注入

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.Set;

@Component
public class ShiroSessionRedisManager {

    @Autowired
    private RedisTemplate<Object,Object> redisTemplate;

    /**
     * 过期时间
     */
//  private Long expire;

    /**
     * 添加缓存数据(给定key已存在,进行覆盖)
     * @param key
     * @param obj
     * @throws DataAccessException
     */
    public <T> void set(String key, T obj) throws DataAccessException{
        final byte[] bkey = key.getBytes();
        final byte[] bvalue = SerializerUtil.serialize(obj);
        redisTemplate.execute(new RedisCallback<Void>() {
            @Override
            public Void doInRedis(RedisConnection connection) throws DataAccessException {
                connection.set(bkey, bvalue);
                return null;
            }
        });
    }

    /**
     * 添加缓存数据(给定key已存在,不进行覆盖,直接返回false)
     * @param key
     * @param obj
     * @return 操作成功返回true,否则返回false
     * @throws DataAccessException
     */
    public <T> boolean setNX(String key, T obj) throws DataAccessException{
        final byte[] bkey = key.getBytes();
        final byte[] bvalue = SerializerUtil.serialize(obj);
        boolean result = redisTemplate.execute(new RedisCallback<Boolean>() {
            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.setNX(bkey, bvalue);
            }
        });

        return result;
    }

    /**
     * 添加缓存数据,设定缓存失效时间
     * @param key
     * @param obj
     * @param expireSeconds 过期时间,单位 秒
     * @throws DataAccessException
     */
    public <T> void setEx(String key, T obj, final long expireSeconds) throws DataAccessException{
        final byte[] bkey = key.getBytes();
        final byte[] bvalue = SerializerUtil.serialize(obj);
        redisTemplate.execute(new RedisCallback<Boolean>() {
            @Override
            public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
                connection.setEx(bkey, expireSeconds, bvalue);
                return true;
            }
        });
    }

    /**
     * 获取key对应value
     * @param key
     * @return
     * @throws DataAccessException
     */
    public <T> T get(final String key) throws DataAccessException{
        byte[] result = redisTemplate.execute(new RedisCallback<byte[]>() {
            @Override
            public byte[] doInRedis(RedisConnection connection) throws DataAccessException {
                return connection.get(key.getBytes());
            }
        });
        if (result == null) {
            return null;
        }
        return SerializerUtil.deserialize(result);
    }

    /**
     * 删除指定key数据
     * @param key
     * @return 返回操作影响记录数
     */
    public Long del(final String key){
        if (StringUtils.isEmpty(key)) {
            return 0l;
        }
        Long delNum = redisTemplate.execute(new RedisCallback<Long>() {
            @Override
            public Long doInRedis(RedisConnection connection) throws DataAccessException {
                byte[] keys = key.getBytes();
                return connection.del(keys);
            }
        });
        return delNum;
    }

    public Set<byte[]> keys(final String key){
        if (StringUtils.isEmpty(key)) {
            return null;
        }
        Set<byte[]> bytesSet = redisTemplate.execute(new RedisCallback<Set<byte[]>>() {
            @Override
            public Set<byte[]> doInRedis(RedisConnection connection) throws DataAccessException {
                byte[] keys = key.getBytes();
                return connection.keys(keys);
            }
        });

        return bytesSet;
    }

}

然后再shiro的config那里注入自己写的sessionDao

@Bean
   public SessionRedisDao getRedisSessionDao(){
      return new SessionRedisDao();
   }

   @Bean(name="sessionManager")
   public DefaultWebSessionManager defaultWebSessionManager() {
      DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
      //sessionManager.setCacheManager(cacheManager());
      sessionManager.setGlobalSessionTimeout(43200000); //12小时
      sessionManager.setDeleteInvalidSessions(true);
      //关键在这里
      sessionManager.setSessionDAO(getRedisSessionDao());
      sessionManager.setSessionValidationSchedulerEnabled(true);
      sessionManager.setDeleteInvalidSessions(true);
      sessionManager.setSessionIdCookie(simpleCookie());
//    sessionManager.setSessionIdCookie(getSessionIdCookie());
      return sessionManager;
   }

   @Bean(name="securityManager")
   public DefaultWebSecurityManager securityManager() {
      DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
      manager.setRealm(realm());
//    manager.setCacheManager(getRedisManager());
      manager.setSessionManager(defaultWebSessionManager());
      return manager;
   }
    //这里是防止shiro的cookie和容器的cookie冲突导致出现刷掉而做
    @Bean
	public SimpleCookie simpleCookie(){
		SimpleCookie simpleCookie = new SimpleCookie();
		simpleCookie.setName("shiro.sesssion");
		simpleCookie.setPath("/");
		return simpleCookie;
	}

万事大吉

然后在登陆那边 去进行排挤的代码 贴一下

Collection<Session> sessions = sessionRedisDao.getActiveSessions();
String principalsSessionValue = null;
for (Session session : sessions) {
   Object attribute = session.getAttribute(DefaultSubjectContext.PRINCIPALS_SESSION_KEY);
   principalsSessionValue = attribute==null?null:attribute.toString();
   if(StringUtils.equals(userVo.getAccount(), principalsSessionValue)){
              // session.setTimeout(0);  //这里就把session清除
      sessionRedisDao.delete(session); //session清除,
          }
      }

猜你喜欢

转载自blog.csdn.net/sevenlxn/article/details/83007711
今日推荐