欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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

程序员文章站 2022-06-05 17:00:41
前言 前段时间做了一个图床的小项目,安全框架使用的是 。为了使用户 小时访问,决定把项目由单机升级为集群部署架构。但是安全框架 只有单机存储的 ,尽管 有基于 的组播/广播实现,然而集群的分布往往是跨网段的,甚至是跨地域的,所以寻求新的方案。 架构 方案 使用 集中存储,实现分布式集群共享用户信息, ......

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

前言

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

架构

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

方案

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

<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

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

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

/**
 * 重写 redismanager
 * 博客:https://blog.52itstyle.vip
 */
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

@data
@configurationproperties(prefix = "redis")
public class redisproperties {

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

配置 shiroconfig

/**
 * shiro权限配置
 * 一定要配置 @configuration 和 @enableconfigurationproperties 注解
 * 博客:https://blog.52itstyle.vip
 */
@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;
    }
}

小结

是不是很爽,以后重启应用再也不用担心用户投诉了?

最后,推荐下小黄图: