(原创)springboot+shiro+redis 限制同用户多次登录(不需要考虑sprinboot、redis版本)

(原创)springboot+shiro+redis 限制同用户多次登录(不需要考虑sprinboot、redis版本)_第1张图片

如果你还在为上面的错误而烦恼。还要听从网上说找合适的版本去解决。来到这篇文章,你的电脑算是保住了。

让我们来分析下问题所在。其实就是实体类RedisSessionDAO中方法getActiveSessions具体是

redisManager.keys行的问题。有兴趣的可以继续找redisManager.keys下面的代码。

(原创)springboot+shiro+redis 限制同用户多次登录(不需要考虑sprinboot、redis版本)_第2张图片

如果考虑换版本之类的,有可能对整体框架都是有影响的。所以我们要换种思路。既然是shiro内在的redis出的问题。那我能不能摒弃他们的redis。答案是:当然可以了!

做法就是自定义个RedisSessionDAO,重写他们的方法。

(原创)springboot+shiro+redis 限制同用户多次登录(不需要考虑sprinboot、redis版本)_第3张图片

 然后你在按照下面这样获取活跃的用户,去处理自己的逻辑

 项目经理都夸你是个人才。

 好了。代码给你放下面了。有问题具体私我。

package com.changfa.config.shiro;

import com.changfa.config.RedisConfig;
import com.changfa.constants.UserConstants;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.crazycake.shiro.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.Serializable;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author wwz
 */
public class CustomRedisSessionDAO  extends RedisSessionDAO{

    private static Logger logger = LoggerFactory.getLogger(RedisSessionDAO.class);
    private static final String DEFAULT_SESSION_KEY_PREFIX = "shiro:session:";
    private String keyPrefix = "shiro:session:";
    private static final long DEFAULT_SESSION_IN_MEMORY_TIMEOUT = 1000L;
    private long sessionInMemoryTimeout = 1000L;
    private static final int DEFAULT_EXPIRE = 1800;
    private int expire = 1800;
    private static final int MILLISECONDS_IN_A_SECOND = 1000;
    private IRedisManager redisManager;
    private RedisSerializer keySerializer = new StringSerializer();
    private RedisSerializer valueSerializer = new ObjectSerializer();
    private static ThreadLocal sessionsInThread = new ThreadLocal();
    private RedisConfig.ByteRedisTemplate redisTemplate;

    public CustomRedisSessionDAO() {
    }

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

    private void saveSession(Session session) throws UnknownSessionException {
        if (session != null && session.getId() != null) {
            if ((long)(this.expire * 1000) < session.getTimeout()) {
                logger.warn("Redis session expire time: " + this.expire * 1000 + " is less than Session timeout: " + session.getTimeout() + " . It may cause some problems.");
            }
            byte[] value = new byte[0];
            try {
                value = valueSerializer.serialize(session);
                redisTemplate.opsForValue().set(this.getRedisSessionKey(session.getId()),value,this.expire, TimeUnit.SECONDS);
            } catch (SerializationException e) {
                e.printStackTrace();
            }
           // this.redisManager.set(key, value, this.expire);
        } else {
            logger.error("session or session id is null");
            throw new UnknownSessionException("session or session id is null");
        }
    }

    @Override
    public void delete(Session session) {
        if (session != null && session.getId() != null) {
            try {
                redisTemplate.delete(this.getRedisSessionKey(session.getId()));

                //this.redisManager.del(this.keySerializer.serialize(this.getRedisSessionKey(session.getId())));
            } catch (Exception var3) {
                logger.error("delete session error. session id=" + session.getId());
            }

        } else {
            logger.error("session or session id is null");
        }
    }
    @Override
    public Collection getActiveSessions() {
        HashSet sessions = new HashSet();

        try {
            Set keys = redisTemplate.keys(this.keyPrefix + "*");
            if (keys != null && keys.size() > 0) {
                Iterator i$ = keys.iterator();

                while(i$.hasNext()) {
                    String key = (String)i$.next();
                    Session s = (Session)valueSerializer.deserialize((byte[]) this.redisTemplate.opsForValue().get(key));
                    Object o = s.getAttribute(UserConstants.USER_KEY);
                    if(o != null){
                        sessions.add(s);
                    }
                }
            }
        } catch (Exception var6) {
            logger.error("get active sessions error.");
        }

        return sessions;
    }

    @Override
    protected Serializable doCreate(Session session) {
        if (session == null) {
            logger.error("session is null");
            throw new UnknownSessionException("session is null");
        } else {
            Serializable sessionId = this.generateSessionId(session);
            this.assignSessionId(session, sessionId);
            this.saveSession(session);
            return sessionId;
        }
    }

    @Override
    protected Session doReadSession(Serializable sessionId) {
        if (sessionId == null) {
            logger.warn("session id is null");
            return null;
        } else {
            Session s = this.getSessionFromThreadLocal(sessionId);
            if (s != null) {
                return s;
            } else {
                logger.debug("read session from redis");

                try {
                    s = (Session)this.valueSerializer.deserialize((byte[]) this.redisTemplate.opsForValue().get(this.getRedisSessionKey(sessionId)));


                   // s = (Session)this.valueSerializer.deserialize(this.redisManager.get(this.keySerializer.serialize(this.getRedisSessionKey(sessionId))));
                    this.setSessionToThreadLocal(sessionId, s);
                } catch (Exception var4) {
                    logger.error("read session error. settionId=" + sessionId);
                }

                return s;
            }
        }
    }

    private void setSessionToThreadLocal(Serializable sessionId, Session s) {
        Map sessionMap = (Map)sessionsInThread.get();
        if (sessionMap == null) {
            sessionMap = new HashMap();
            sessionsInThread.set(sessionMap);
        }

        SessionInMemory sessionInMemory = new SessionInMemory();
        sessionInMemory.setCreateTime(new Date());
        sessionInMemory.setSession(s);
        ((Map)sessionMap).put(sessionId, sessionInMemory);
    }

    private Session getSessionFromThreadLocal(Serializable sessionId) {
        Session s = null;
        if (sessionsInThread.get() == null) {
            return null;
        } else {
            Map sessionMap = (Map)sessionsInThread.get();
            SessionInMemory sessionInMemory = (SessionInMemory)sessionMap.get(sessionId);
            if (sessionInMemory == null) {
                return null;
            } else {
                Date now = new Date();
                long duration = now.getTime() - sessionInMemory.getCreateTime().getTime();
                if (duration < this.sessionInMemoryTimeout) {
                    s = sessionInMemory.getSession();
                    logger.debug("read session from memory");
                } else {
                    sessionMap.remove(sessionId);
                }

                return s;
            }
        }
    }

    private String getRedisSessionKey(Serializable sessionId) {
        return this.keyPrefix + sessionId;
    }

    public RedisConfig.ByteRedisTemplate getRedisTemplate() {
        return redisTemplate;
    }

    public void setRedisTemplate(RedisConfig.ByteRedisTemplate redisTemplate) {
        this.redisTemplate = redisTemplate;
    }
}

你可能感兴趣的:(架构,redis,springboot,shiro,springboot,shiro源码)