springboot+shiro+redis(单机+集群自动切换) - Go语言中文社区

springboot+shiro+redis(单机+集群自动切换)


根据项目需要,整合了springboot+shiro+redis单机、集群,有需要的小伙伴参考吧,有什么不懂的可以加群问,本人不喜欢写文字,直接上代码
 

 

                                      

                                 

  redis配置文件:application-dev.yml


spring:
    redis:
        isJq: false #是否开启集群
        host: 127.0.0.1
        port: 6379
        password: hn863@soft
        # 连接超时时间(毫秒)
        timeout: 15000
        clusterNodes: 192.168.3.131:7000,192.168.3.131:7001,192.168.3.131:7002,192.168.3.131:7003,192.168.3.131:7004,192.168.3.131:7005
        max-redirects: 3
        pool:
        # 连接池中的最大空闲连接
        max-idle: 300
        # 连接池中的最小空闲连接
        min-idle: 10
        # 连接池最大连接数(使用负值表示没有限制)
        max-total: -1   #如果是jedis 2.4以后用该属性(2.4版本以前使用max-active)
        # 连接池最大阻塞等待时间(使用负值表示没有限制)
        max-wait: -1
        #连接的最小空闲时间 默认1800000毫秒(30分钟)
        minEvictableIdleTimeMillis: 300000
        #每次释放连接的最大数目,默认3
        numTestsPerEvictionRun: 1024
        #逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
        timeBetweenEvictionRunsMillis: 30000
        #是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
        testOnBorrow: true
        #在空闲时检查有效性, 默认false
        testWhileIdle: true
         

 

 

ShiroConfig:


package com.expo.system.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.expo.common.config.Constant;
import com.expo.common.redis.shiro.RedisSessionDAO;
import com.expo.common.redis.shiro.ShiroRedisCacheManager;
import com.expo.common.utils.RedisUtil;
import com.expo.system.shiro.MyShiroFilterFactoryBean;
import com.expo.system.shiro.UserRealm;
import net.sf.ehcache.CacheManager;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.eis.MemorySessionDAO;
import org.apache.shiro.session.mgt.eis.SessionDAO;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.web.mgt.CookieRememberMeManager;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Set;


/**
 * @author bootdo 1992lcg@163.com
 */
@Configuration
public class ShiroConfig {
    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.password}")
    private String password;
    @Value("${spring.redis.port}")
    private int port;
    @Value("${spring.redis.timeout}")
    private int timeout;
    @Value("${spring.cache.type}")
    private String cacheType;

    @Value("${server.session-timeout}")
    private int tomcatTimeout;

    @Value("${spring.redis.isJq}")
    private boolean isJq;

    @Value("${spring.redis.clusterNodes}")
    private String clusterNodes;


    @Value("${spring.redis.pool.max-idle}")
    private int maxIdle;

    @Value("${spring.redis.pool.min-idle}")
    private int minIdle;

    @Value("${spring.redis.pool.max-total}")
    private int maxTotal;

    @Value("${spring.redis.pool.max-wait}")
    private int maxWait;

    @Value("${spring.redis.pool.minEvictableIdleTimeMillis}")
    private long minEvictableIdleTimeMillis;

    @Value("${spring.redis.pool.numTestsPerEvictionRun}")
    private int numTestsPerEvictionRun;

    @Value("${spring.redis.pool.timeBetweenEvictionRunsMillis}")
    private long timeBetweenEvictionRunsMillis;

    @Value("${spring.redis.pool.testOnBorrow}")
    private boolean testOnBorrow;

    @Value("${spring.redis.pool.testWhileIdle}")
    private boolean testWhileIdle;

    @Value("${spring.redis.max-redirects}")
    private int maxRedirectsac;



    /**
     * JedisPoolConfig 连接池
     * @return
     */
    @Bean
    public JedisPoolConfig jedisPoolConfig() {
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        // 最大空闲数
        jedisPoolConfig.setMaxIdle(maxIdle);
        // 连接池的最大数据库连接数
        jedisPoolConfig.setMaxTotal(maxTotal);
        // 最大建立连接等待时间
        jedisPoolConfig.setMaxWaitMillis(maxWait);
        // 逐出连接的最小空闲时间 默认1800000毫秒(30分钟)
        jedisPoolConfig.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        // 每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认3
        jedisPoolConfig.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
        // 逐出扫描的时间间隔(毫秒) 如果为负数,则不运行逐出线程, 默认-1
        jedisPoolConfig.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
        // 是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个
        jedisPoolConfig.setTestOnBorrow(testOnBorrow);
        // 在空闲时检查有效性, 默认false
        jedisPoolConfig.setTestWhileIdle(testWhileIdle);
        return jedisPoolConfig;
    }

    @Bean
    public RedisClusterConfiguration redisClusterConfiguration(){
        RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
        //Set<RedisNode> clusterNodes
        String[] serverArray = clusterNodes.split(",");

        Set<RedisNode> nodes = new HashSet<RedisNode>();

        for(String ipPort:serverArray){
            String[] ipAndPort = ipPort.split(":");
            nodes.add(new RedisNode(ipAndPort[0].trim(),Integer.valueOf(ipAndPort[1])));
        }

        redisClusterConfiguration.setClusterNodes(nodes);
        redisClusterConfiguration.setMaxRedirects(maxRedirectsac);

        return redisClusterConfiguration;
    }

    /**
     * 单机版和集群版配置
     * @Title: JedisConnectionFactory
     * @param @param jedisPoolConfig
     * @param @return
     * @return JedisConnectionFactory
     * @autor lpl
     * @date 2018年2月24日
     * @throws
     */
    @Bean
    public JedisConnectionFactory edisConnectionFactory(JedisPoolConfig jedisPoolConfig, RedisClusterConfiguration redisClusterConfiguration){
        //是否开启集群模式
        if(isJq){
            JedisConnectionFactory JedisConnectionFactory = new JedisConnectionFactory(redisClusterConfiguration,jedisPoolConfig);
            JedisConnectionFactory.setPassword(password);
            return JedisConnectionFactory;
        }else{
            JedisConnectionFactory JedisConnectionFactory = new JedisConnectionFactory(jedisPoolConfig);
            //连接池
            JedisConnectionFactory.setPoolConfig(jedisPoolConfig);
            //IP地址
            JedisConnectionFactory.setHostName(host);
            //端口号
            JedisConnectionFactory.setPort(port);
            //如果Redis设置有密码
            JedisConnectionFactory.setPassword(password);
            //客户端超时时间单位是毫秒
            JedisConnectionFactory.setTimeout(timeout);
            return JedisConnectionFactory;
        }
    }


    /**
     * 实例化 RedisTemplate 对象
     *
     * @return
     */
    @Bean
    public RedisTemplate init(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate redisTemplate = new RedisTemplate();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;
    }



    /**
     * 注入封装RedisTemplate
     * @Title: redisUtil
     * @return RedisUtil
     * @autor lpl
     * @date 2017年12月21日
     * @throws
     */
    @Bean(name = "redisUtil")
    public RedisUtil redisUtil(RedisTemplate redisTemplate) {
        RedisUtil redisUtil = new RedisUtil();
        redisUtil.setRedisTemplate(redisTemplate);
        return redisUtil;
    }



    @Bean
    public SecurityManager securityManager(RedisConnectionFactory redisConnectionFactory) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //设置realm.
        securityManager.setRealm(userRealm());
        // 自定义缓存实现 使用redis
        if (Constant.CACHE_TYPE_REDIS.equals(cacheType)) {
            securityManager.setCacheManager(cacheManager(redisConnectionFactory));
        } else {
            securityManager.setCacheManager(ehCacheManager());
        }
        securityManager.setSessionManager(sessionManager(redisConnectionFactory));
        securityManager.setRememberMeManager(rememberMeManager());
        return securityManager;
    }


    @Bean
    public DefaultWebSessionManager sessionManager(RedisConnectionFactory redisConnectionFactory){
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setGlobalSessionTimeout(tomcatTimeout * 1000);
        sessionManager.setSessionDAO(sessionDAO(redisConnectionFactory));
        return sessionManager;
    }


    /**
     * ShiroDialect,为了在thymeleaf里使用shiro的标签的bean
     *
     * @return
     */
    @Bean
    public ShiroDialect shiroDialect() {
        return new ShiroDialect();
    }


    @Bean
    MyShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        MyShiroFilterFactoryBean shiroFilterFactoryBean = new MyShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setLoginUrl("/login");
        shiroFilterFactoryBean.setSuccessUrl("/index");
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");

        LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        filterChainDefinitionMap.put("/css/**", "anon");
        filterChainDefinitionMap.put("/js/**", "anon");
        filterChainDefinitionMap.put("/fonts/**", "anon");
        filterChainDefinitionMap.put("/img/**", "anon");
        filterChainDefinitionMap.put("/favicon.ico", "anon");
        filterChainDefinitionMap.put("/docs/**", "anon");
        filterChainDefinitionMap.put("/druid/**", "anon");
        filterChainDefinitionMap.put("/upload/**", "anon");
        filterChainDefinitionMap.put("/files/**", "anon");
        filterChainDefinitionMap.put("/front/**", "anon");
        filterChainDefinitionMap.put("/expo/expoCodeprint/**", "anon");
        filterChainDefinitionMap.put("/expo/zz/**", "anon");
        filterChainDefinitionMap.put("/indexFoot/**", "anon");
        filterChainDefinitionMap.put("/sys/exhibitor/register/**", "anon");
        filterChainDefinitionMap.put("/sys/exhibitor/jump/**", "anon");
        filterChainDefinitionMap.put("/logout", "anon");
        filterChainDefinitionMap.put("/czsLogin", "anon");
        filterChainDefinitionMap.put("/hnfair", "anon");
        filterChainDefinitionMap.put("/touqiahui/**", "anon");
        filterChainDefinitionMap.put("/7286272117.txt", "anon");
        filterChainDefinitionMap.put("/MP_verify_*", "anon");
        filterChainDefinitionMap.put("/", "anon");
        filterChainDefinitionMap.put("/**", "user");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }



    @Bean
    UserRealm userRealm() {
        UserRealm userRealm = new UserRealm();
        return userRealm;
    }


    /**
     * 开启shiro aop注解支持.
     * 使用代理方式;所以需要开启代码支持;
     *
     * @param securityManager
     * @return
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }


    /**
     * cacheManager 缓存 redis实现
     * 使用的是shiro-redis开源插件
     *
     * @return
     */
    public ShiroRedisCacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        return new ShiroRedisCacheManager(init(redisConnectionFactory));
    }


    @Bean
    public SessionDAO sessionDAO(RedisConnectionFactory redisConnectionFactory) {
        if (Constant.CACHE_TYPE_REDIS.equals(cacheType)) {
            RedisSessionDAO redisSessionDAO=new RedisSessionDAO(redisUtil(init(redisConnectionFactory)));
            return  redisSessionDAO;
           // return new EnterpriseCacheSessionDAO();
        } else {
            return new MemorySessionDAO();
        }
    }

    //@Bean
    public EhCacheManager ehCacheManager() {
        EhCacheManager em = new EhCacheManager();
        em.setCacheManager(CacheManager.create());
        return em;
    }

    @Bean
    public SimpleCookie rememberMeCookie(){
        //这个参数是cookie的名称,对应前端的checkbox的name = rememberMe
        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
        //<!-- 记住我cookie生效时间30天 ,单位秒;-->
        simpleCookie.setMaxAge(259200);
        return simpleCookie;
    }
    /**
     * cookie管理对象;
     * @return
     */
    @Bean
    public CookieRememberMeManager rememberMeManager(){
        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
        cookieRememberMeManager.setCookie(rememberMeCookie());
        return cookieRememberMeManager;
    }

    public boolean getIsJq() {
        return isJq;
    }
}



RedisSessionDAO:
package com.expo.common.redis.shiro;

import com.expo.common.utils.RedisUtil;
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 java.io.Serializable;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;

/**
 * @author bootdo 1992lcg@163.com
 * @version V1.0
 */
public class RedisSessionDAO extends AbstractSessionDAO {

    private static Logger logger = LoggerFactory.getLogger(RedisSessionDAO.class);

    private RedisUtil redisUtil;

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


    public RedisSessionDAO(RedisUtil redisUtil){
        this.redisUtil = redisUtil;
    }

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

    /**
     * save session
     * @param session
     * @throws UnknownSessionException
     */
    private void saveSession(Session session) throws UnknownSessionException{
        if(session == null || session.getId() == null){
            logger.error("session or session id is null");
            return;
        }
        String key = getStringKey(session.getId());
        byte[] value = SerializeUtils.serialize(session);
        redisUtil.setString(key,value);
    }

    @Override
    public void delete(Session session) {
        if(session == null || session.getId() == null){
            logger.error("session or session id is null");
            return;
        }
        redisUtil.delString(getStringKey(session.getId()));
    }

    @Override
    public Collection<Session> getActiveSessions() {
        Set<Session> sessions = new HashSet<Session>();
        Set<String> keys=redisUtil.keysString(this.keyPrefix + "*");
        if(keys != null && keys.size()>0){
            for(String key:keys){
                Session s = (Session)SerializeUtils.deserialize((byte[])redisUtil.getString(key));
                sessions.add(s);
            }
        }

        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)SerializeUtils.deserialize((byte[])redisUtil.getString(this.getStringKey(sessionId)));
        return s;
    }


    /**
     * 获得byte型的key
     * @param sessionId
     * @return
     */
    private byte[] getByteKey(Serializable sessionId){
        String preKey = this.keyPrefix + sessionId;
        return preKey.getBytes();
    }

    /**
     * 获得String型的key
     * @param sessionId
     * @return
     */
    private String getStringKey(Serializable sessionId){
        String preKey = this.keyPrefix + sessionId;
        return preKey;
    }
}

 

ShiroRedisCacheManager:
package com.expo.common.redis.shiro;

import org.apache.shiro.cache.AbstractCacheManager;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.*;

public class ShiroRedisCacheManager extends AbstractCacheManager{
    private RedisTemplate redisTemplate;

    public ShiroRedisCacheManager(RedisTemplate redisTemplate){
        this.redisTemplate = redisTemplate;
    }

    @Override
    protected Cache createCache(String name) throws CacheException {
        return new ShiroRedisCache(redisTemplate,name);
    }
}

class ShiroRedisCache<K,V> implements Cache<K,V> {
    private RedisTemplate redisTemplate;
    private String prefix = "random_shiro_redis";

    public String getPrefix() {
        return prefix+":";
    }

    public void setPrefix(String prefix) {
        this.prefix = prefix;
    }

    public ShiroRedisCache(RedisTemplate redisTemplate){
        this.redisTemplate = redisTemplate;
    }

    public ShiroRedisCache(RedisTemplate redisTemplate,String prefix){
        this(redisTemplate);
        this.prefix = prefix;
    }

    @Override
    public V get(K k) throws CacheException {
        if (k == null) {
            return null;
        }
        String key = getStringKey(k);
        return (V)redisTemplate.opsForValue().get(key);

    }

    @Override
    public V put(K k, V v) throws CacheException {
        if (k== null || v == null) {
            return null;
        }

        String key = getStringKey(k);
        redisTemplate.opsForValue().set(key, v);
        return v;
    }

    @Override
    public V remove(K k) throws CacheException {
        if(k==null){
            return null;
        }
        String key =getStringKey(k);
        V v = (V)redisTemplate.opsForValue().get(key);
        redisTemplate.delete(key);
        return v;
    }

    @Override
    public void clear() throws CacheException {
        redisTemplate.getConnectionFactory().getConnection().flushDb();

    }

    @Override
    public int size() {
        return redisTemplate.getConnectionFactory().getConnection().dbSize().intValue();
    }

    @Override
    public Set<K> keys() {
        String keyall = getPrefix()+"*";
        Set<String> keys = redisTemplate.keys(keyall);
        Set<K> sets = new HashSet<>();
        for (String key:keys) {
            sets.add((K)key);
        }
        return sets;
    }

    @Override
    public Collection<V> values() {
        Set<K> keys = keys();
        List<V> values = new ArrayList<>(keys.size());
        for(K k :keys){
            values.add(get(k));
        }
        return values;
    }

    private byte[] getBytesKey(K key){
        if(key instanceof String){
            String prekey = this.getPrefix() + key;
            return prekey.getBytes();
        }else {
            return SerializeUtils.serialize(key);
        }
    }

    private String getStringKey(K key) {
            String prekey = this.getPrefix() + key;
            return prekey;
    }

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/wang1988081309/article/details/84445028
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2021-06-12 20:40:13
  • 阅读 ( 1244 )
  • 分类:Redis

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢