前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringBoot 2.x 开发案例之 Shiro 整合 Redis

SpringBoot 2.x 开发案例之 Shiro 整合 Redis

作者头像
小柒2012
发布2020-02-12 18:56:09
2.3K0
发布2020-02-12 18:56:09
举报
文章被收录于专栏:IT笔记

前言

前段时间做了一个图床的小项目,安全框架使用的是Shiro。为了使用户7x24小时访问,决定把项目由单机升级为集群部署架构。但是安全框架shiro只有单机存储的SessionDao,尽管Shrio有基于Ehcache-rmi的组播/广播实现,然而集群的分布往往是跨网段的,甚至是跨地域的,所以寻求新的方案。

架构

方案

使用 redis 集中存储,实现分布式集群共享用户信息,这里我们采用第三方开源插件crazycake来实现,pom.xml 引入:

代码语言:javascript
复制
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
    <groupId>org.crazycake</groupId>
    <artifactId>shiro-redis</artifactId>
    <version>3.2.3</version>
</dependency>

配置 application.properties

代码语言:javascript
复制
# Redis
# 数据库索引(默认为0)
redis.database=0
# 服务器地址 变更为自己的
redis.host=127.0.0.1
# 服务器连接端口
redis.port=6379
# 服务器连接密码,如果不设置密码注释掉即可
# redis.password=
# 连接超时时间(毫秒)
redis.timeout=30000

本来crazycake插件已经实现了RedisManager,但是参数不可配,这里我们需要自己重写一下:

代码语言:javascript
复制
public class RedisManager extends WorkAloneRedisManager implements IRedisManager {

    private RedisProperties redis;

    private JedisPool jedisPool;

    public RedisManager(RedisProperties redis) {
        this.redis = redis;
    }

    private void init() {
        synchronized(this) {
            if (this.jedisPool == null) {
                this.jedisPool = new JedisPool(this.getJedisPoolConfig(), redis.getHost(), redis.getPort(),
                        redis.getTimeout(), redis.getPassword(), redis.getDatabase());
            }
        }
    }

    @Override
    protected Jedis getJedis() {
        if (this.jedisPool == null) {
            this.init();
        }
        return this.jedisPool.getResource();
    }
}

参数配置 RedisProperties

代码语言:javascript
复制
@Data
@ConfigurationProperties(prefix = "redis")
public class RedisProperties {

    private String host;
    private int port;
    private int timeout;
    private String password;
    private int database;
}

配置 ShiroConfig

代码语言:javascript
复制
/**
 * Shiro权限配置
 * 一定要配置 @Configuration 和 @EnableConfigurationProperties 注解
 */
@Configuration
@EnableConfigurationProperties({RedisProperties.class})
public class ShiroConfig {

    private RedisProperties redis;

    public ShiroConfig(RedisProperties redis) {
        this.redis = redis;
    }

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

    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean (SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setLoginUrl("/index.html");
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");
        // 拦截器
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        /**
         * 静态文件
         */
        filterChainDefinitionMap.put("/file/**","anon");
        /**
         * 登录注册
         */
        filterChainDefinitionMap.put("/register.shtml","anon");
        filterChainDefinitionMap.put("/login.shtml","anon");
        /**
         * 管理后台
         */
        filterChainDefinitionMap.put("/sys/**", "roles[admin]");
        filterChainDefinitionMap.put("/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    @Bean
    public SessionsSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm());
        securityManager.setCacheManager(cacheManager());
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }
    @Bean
    public DefaultWebSessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionIdUrlRewritingEnabled(false);
        sessionManager.setSessionDAO(redisSessionDAO());
        return sessionManager;
    }
    @Bean
    public ShiroDialect shiroDialect(){
        return new ShiroDialect();
    }

    /**
     * cacheManager 缓存 redis实现
     * @return
     */
    public RedisCacheManager cacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        return redisCacheManager;
    }

    /**
     * 配置shiro redisManager
     * @return
     */
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager(redis);
        return redisManager;
    }

    /**
     * RedisSessionDAO shiro sessionDao层的实现
     * 原理就是重写 AbstractSessionDAO
     * 有兴趣的小伙伴自行阅读源码
     */
    @Bean
    public RedisSessionDAO redisSessionDAO() {
        RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
        redisSessionDAO.setRedisManager(redisManager());
        return redisSessionDAO;
    }
}

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-01-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 架构
  • 方案
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档