SpringBoot中shiro 添加sessionManager和cacheManager

18 篇文章 0 订阅

参考资料:
https://github.com/Pramy/shiro-redis-spring-boot-starter
https://github.com/alexxiyang/shiro-redis

Shiro 缓存管理

RedisCache.class

@Slf4j
@Component
public class RedisCache implements Cache<Object, Object> {

    @Resource(name = "myRedisTemplate")
    private RedisTemplate<Object, Object> client;

    private String keyPrefix;
    private long ttl;

    public RedisCache(RedisCacheProperties redisCacheProperties) {
        this.keyPrefix = redisCacheProperties.getKeyPrefix();
        this.ttl = redisCacheProperties.getValueCacheExpire();
    }

    private Object getKey(Object k) {
        return this.keyPrefix + (k == null ? "*" : k);
    }

    @Override
    public Object get(Object o) throws CacheException {
        return client.opsForValue().get(getKey(o));
    }

    @Override
    public Object put(Object o, Object o2) throws CacheException {
        if (ttl >= 0) {
            client.opsForValue().set(getKey(o), o2, ttl, TimeUnit.MILLISECONDS);
        } else {
            client.opsForValue().set(getKey(o), o2);
        }
        return o2;
    }

    @Override
    public Object remove(Object o) throws CacheException {
        Object result = get(o);
        client.delete(getKey(o));
        return result;
    }

    @Override
    public void clear() throws CacheException {
        client.delete(getKey("*"));
    }

    @Override
    public int size() {
        return keys().size();
    }

    @Override
    public Set<Object> keys() {
        return client.keys(getKey("*"));
    }

    @Override
    public Collection<Object> values() {
        return client.opsForValue().multiGet(keys());
    }
}

RedisCacheManager.class

@Component("myRedisCacheManager")
public class RedisCacheManager implements CacheManager {

    @Resource
    private RedisCache client;

    @SuppressWarnings("unchecked")
    @Override
    public <K, V> Cache<K, V> getCache(String name) throws CacheException {
        return (Cache<K, V>) client;
    }

}

Shiro Session管理

RedisSessionDao.class

@Component
public class RedisSessionDao extends AbstractSessionDAO {

    private final Logger logger = LoggerFactory.getLogger(RedisSessionDao.class);

    private String keyPrefix;

    private Long ttl;

    private RedisTemplate<Object, Object> client;

    private Cache<Serializable, Session> caches;

    public RedisSessionDao(@Qualifier("myRedisTemplate") RedisTemplate<Object, Object> redisTemplate,
                           RedisCacheProperties redisCacheProperties) {
        init(redisCacheProperties.getSessionPrefix(), redisCacheProperties.getSessionCacheExpire(), redisTemplate);
    }

    @Override
    protected Serializable doCreate(Session session) {
        logger.debug("doCreate");
        if (session == null) {
            logger.error("session is null");
            throw new SessionException("session is null");
        }
        Serializable id = super.generateSessionId(session);
        ((SimpleSession) session).setId(id);
        saveSession(session);
        return id;
    }

    @Override
    protected Session doReadSession(Serializable sessionId) {
        if (sessionId == null) {
            logger.error("session id is null");
            throw new SessionException("session id is null");
        }
        Session session = caches.getIfPresent(sessionId);
        if (session == null) {
            logger.debug("doReadSession " + sessionId + " from redis");
            session = (Session) client.opsForValue().get(getKey(sessionId));
            if (session != null) {
                caches.put(sessionId, session);
            }
        }
        return session;
    }

    @Override
    public void update(Session session) throws UnknownSessionException {

        if (session instanceof ValidatingSession && !((ValidatingSession) session).isValid()) {
            delete(session);
        } else {
            logger.debug("update" + session.getId() + " session");
            saveSession(session);
        }
    }

    @Override
    public void delete(Session session) {
        if (session == null || session.getId() == null) {
            logger.error("session or session id is null");
            throw new UnknownSessionException("session or session id is null");
        }
        caches.invalidate(session.getId());

        logger.debug("delete " + session.getId() + " from redis");
        Object key = getKey(session.getId());
        client.delete(key);
    }

    @Override
    public Collection<Session> getActiveSessions() {
        List<Session> result = new ArrayList<>();
        Set<Object> keys = client.keys(getKey("*"));
        if (CollectionUtils.isEmpty(keys)) {
            return result;
        }
        List<Object> values = client.opsForValue().multiGet(keys);
        if (CollectionUtils.isEmpty(values)) {
            return result;
        }
        for (Object o : values) {
            result.add((Session) o);
        }
        return result;
    }

    private void saveSession(Session session) {
        if (session == null || session.getId() == null) {
            logger.error("session or session id is null");
            throw new UnknownSessionException("session or session id is null");
        }

        Object key = getKey(session.getId());
        logger.debug("save session to redis");
        client.opsForValue().set(key, session, ttl, TimeUnit.MILLISECONDS);
        caches.put(session.getId(), session);
    }

    private Object getKey(Object o) {
        return keyPrefix + (o == null ? "*" : o);
    }


    private void init(String keyPrefix, Long ttl, RedisTemplate<Object, Object> client) {
        this.keyPrefix = keyPrefix;
        if (ttl > 0) {
            this.ttl = ttl;
        } else {
            this.ttl = 0L;
            logger.debug("session expire must be more than 0");
        }
        this.client = client;
        caches = CacheBuilder.newBuilder()
                .initialCapacity(500)
                .weakValues()
                .maximumSize(1000)
                .expireAfterAccess(1, TimeUnit.MINUTES)
                .build();
    }

}

其他配置类:
RedisCacheProperties.class

@Data
@Component
@ConfigurationProperties(prefix = "spring.shiro.redis")
public class RedisCacheProperties {

    public static final long MILLIS_PER_SECOND = 1000;
    public static final long MILLIS_PER_MINUTE = 60 * MILLIS_PER_SECOND;
    public static final long MILLIS_PER_HOUR = 60 * MILLIS_PER_MINUTE;
    public static final long MILLIS_DAY = 24 * MILLIS_PER_HOUR;


    private String keyPrefix = "shiro:cache:";

    private String sessionPrefix = "shiro:session:";

    /**
     * Time unit:millis
     */
    private Long sessionTimeOut = 30 * MILLIS_PER_MINUTE;

    /**
     * Time unit:millis
     */
    private Long sessionCacheExpire = MILLIS_DAY;

    /**
     * Time unit:millis
     */
    private Long valueCacheExpire = -1L;

    private boolean isSerializeTransient = true;

    private Map<String, String> filterChain;

    private List<Class<?>> classList;

    public Map<String, String> getFilterChain() {
        return filterChain;
    }

    public void setFilterChain(Map<String, String> filterChain) {
        this.filterChain = filterChain;
    }

}

RedisShiroBeanConfig.class

@Configuration
public class RedisShiroBeanConfig {

    @Bean(name = "myRedisTemplate")
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        redisTemplate.setKeySerializer(stringRedisSerializer);
        redisTemplate.setHashKeySerializer(stringRedisSerializer);
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;
    }

    @Bean(name = "myRedisSessionManager")
    public SessionManager sessionManager(RedisSessionDao redisSessionDao,
                                         RedisCacheProperties redisCacheProperties,
                                         RedisCacheManager redisCacheManager) {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionDAO(redisSessionDao);
        long time = redisCacheProperties.getSessionTimeOut();
        sessionManager.setGlobalSessionTimeout(time > 0 ? time : RedisCacheProperties.MILLIS_PER_MINUTE * 30);
        sessionManager.setCacheManager(redisCacheManager);
        return sessionManager;
    }

}

最后在ShiroCofnig类中添加

@Bean
    public SessionsSecurityManager securityManager(
            @Qualifier("myRedisCacheManager") RedisCacheManager redisCacheManager,
            @Qualifier("myRedisSessionManager") SessionManager myRedisSessionManager) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(realm());

        securityManager.setCacheManager(redisCacheManager);

        // 使用 spring-session-data-redis 实现分布式session管理
         securityManager.setSessionManager(myRedisSessionManager);

        return securityManager;
    }

参考资料:
https://github.com/Pramy/shiro-redis-spring-boot-starter
https://github.com/alexxiyang/shiro-redis

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值