首页 > 其他分享 >shiro缓存配置流程

shiro缓存配置流程

时间:2024-01-20 22:06:16浏览次数:29  
标签:缓存 return 流程 shiroCacheManager session redisCacheManager public shiro


以前搞shiro的时候没有刻意去研究过这些配置文件,导致用shiro的时候也是迷迷糊糊,惭愧啊,要想成为人上人,读源码,懂配置是真滴重要!

安全管理器配置(SecurityManager )

配置项

意思


setCacheManager

配置缓存管理器用来缓存realm和session信息


setRealm

登录时假如用的UsernamePasswordToken,会来调用我们这里设置过的realm中找符合条件的realm,执行对应的逻辑


setSessionManager

配置会话管理器

/**
     * @param
     * @method 这里设置了shiroCacheManager,表示要缓存loginRealm,以及会话session。
     * 这里如果不设置shiroCacheManager,由于shiroSessionDao(shiroCacheManager)已经注入过shiroCacheManager
     * session信息也是能被缓存的
     */
    @Bean
    public SecurityManager securityManager() {
        DefaultSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setCacheManager(shiroCacheManager);
        securityManager.setRealm(loginRealm());
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }

    @Bean
    public loginRealm loginRealm() {
        return new loginRealm();
    }
    
    /**
     * @param
     * @method DefaultWebSessionManager的配置,设置了sessionDAO
     */
    @Bean
    public SessionManager sessionManager() {
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionDAO(sessionDAO());
        return sessionManager;
    }

    /**
     * @param
     * @method 这里配置shiro的会话底层的缓存管理器,底层用的是redis缓存会话
     */
    @Bean
    public SessionDAO sessionDAO() {
        shiroSessionDao shiroSessionDao = new shiroSessionDao(shiroCacheManager);
        return shiroSessionDao;
    }

注意点:

/**
     * @param
     * @method 这里设置了shiroCacheManager,表示要缓存loginRealm,以及会话session。
     * 这里如果不设置shiroCacheManager,由于shiroSessionDao(shiroCacheManager)已经注入过shiroCacheManager
     * session信息也是能被缓存的
     */

    @Bean
    public SecurityManager securityManager() {
        DefaultSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setCacheManager(shiroCacheManager);
        securityManager.setRealm(loginRealm());
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }

为什么要配置缓存管理器(setCacheManager)?

不配置缓存管理器: 每次去访问那些需要权限的页面的时候都要执行授权的操作,授权里面又要查权限表,这个页面才会知道到底你是否有权限访问,带来的开销是巨大的。
配置缓存管理器: 只需从缓存里面拿取权限信息就行。

开始配置

首先我们要明白我们要配置的是shiro中的CacheManager

shiro缓存配置流程_java

shiro缓存配置流程_分布式_02

思路:知道这个那就简单了,直接编写其实现类就是了,只不过获取cache的途径是从shiro.cache中获取而已,而shiro.cache中获取cahce的途径是从redis中获取的,怎么从redis获取的?我们直接往shiro.cache中注入一个RedisCacheManager 不就得了。进而实现shiro.cache中的crud,完事。

public class shiroCacheManager implements CacheManager {

    private static RedisCacheManager redisCacheManager;

    public shiroCacheManager(RedisCacheManager redisCacheManager) {
        this.redisCacheManager = redisCacheManager;
    }

    @Override
    public <K, V> Cache<K, V> getCache(String cacheName) throws CacheException {
        return new shiroCache(redisCacheManager, cacheName);
    }
}

自定义Cache<k, v>(shiro提供的cache接口)

根据传进来的 RedisCacheManager 获取对应组的 spring.cache(RedisCacheManager是由Spring提供的,获取到的cache 是spring.cache),然后用这个spring.cache进行crud操作。为了让代码复用性高一点我们用范型来做处理

/**
 * @author 张子行
 * @class 自定义shiro缓存
 */
public class shiroCache<k, v> implements Cache<k, v> {
    private  org.springframework.cache.Cache springCache;
    private  RedisCacheManager redisCacheManager;
    private  String cacheName;
    public shiroCache(RedisCacheManager redisCacheManager, String cacheName) {
        this.springCache = redisCacheManager.getCache(cacheName);
        this.redisCacheManager = redisCacheManager;
        this.cacheName = cacheName;
    }

    /**
     * @param
     * @method 缓存的获取
     * 在访问需要权限的页面时会,从缓存中拉去权限信息,看你是否有权访问
     */
    @Override
    public v get(k k) throws CacheException {
        System.out.println("get():"+cacheName);
        org.springframework.cache.Cache.ValueWrapper valueWrapper = springCache.get(k);
        if (valueWrapper != null) {
            return (v) valueWrapper.get();
        }
        return null;
    }

    /**
     * @param
     * @method 缓存的放入,在会话开始的时候会把session信息放入缓存,
     * 在subject.login()的时候会把授权信息放入缓存
     */
    @Override
    public v put(k k, v v) throws CacheException {
        System.out.println("put():"+cacheName);
        springCache.put(k, v);
        return v;
    }

    /**
     * @param
     * @method 缓存的清除单个(在Subject subject = SecurityUtils.getSubject();
     *         subject.logout();的时候会清除相应的授权认证缓存,我测试的时候session缓存也会被清除)
     */
    @Override
    public v remove(k k) throws CacheException {
        System.out.println("remove():"+cacheName);
        v v = this.get(k);
        springCache.evict(k);
        return v;
    }

    /**
     * @param
     * @method 缓存的全部删除
     */
    @Override
    public void clear() throws CacheException {
        System.out.println("clear(): "+cacheName);
        springCache.clear();
    }

    /**
     * @param
     * @method 缓存的个数
     */
    @Override
    public int size() {
        System.out.println("size(): "+cacheName);
        int size = this.keys().size();
        return size;
    }

    /**
     * @param
     * @method 缓存的所有key
     */
    @Override
    public Set<k> keys() {
        System.out.println("keys(): "+cacheName);
        Collection<String> cacheNames = redisCacheManager.getCacheNames();
        return (Set<k>) cacheNames;
    }

    /**
     * @param
     * @method 缓存的所有values
     */
    @Override
    public Collection<v> values() {
        System.out.println("values(): "+cacheName);
        ArrayList<v> data = new ArrayList<>();
        Set<k> keys = this.keys();
        for (k k : keys) {
            data.add(this.get(k));
        }
        return data;
    }
}

自定义CachingSessionDAO

/**
 * @author 张子行
 * @class 自定义CachingSessionDAO
 */
public class shiroSessionDao extends CachingSessionDAO {

    private static Serializable sessionId = null;

    /**
     * @param
     * @method 提供缓存session的扩展方法,到时候用的时候,
     * 想用什么缓存session信息,直接注入对应的CacheManager就行
     */
    public shiroSessionDao(CacheManager cacheManager) {
        super.setCacheManager(cacheManager);
    }

    @Override
    protected void doUpdate(Session session) {
        System.out.println("更新session");
    }

    @Override
    protected void doDelete(Session session) {
        System.out.println("删除session");
    }

    @Override
    protected Serializable doCreate(Session session) {
        sessionId = "666";
        assignSessionId(session, sessionId);
        return sessionId;
    }

    @Override
    protected Session doReadSession(Serializable sessionId) {
        System.out.println("读取session");
        return null;
    }

    /**
     * @param
     * @method 把session对象转化为byte保存到redis中
     */
    public byte[] sessionToByte(Session session) {
        ByteArrayOutputStream bo = new ByteArrayOutputStream();
        byte[] bytes = null;
        try {
            ObjectOutputStream oo = new ObjectOutputStream(bo);
            oo.writeObject(session);
            bytes = bo.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return bytes;
    }
}

注入缓存管理器

/**
 * @author 张子行
 * @class 缓存管理器
 */
@Configuration
public class cacheConfig {
    @Autowired
    RedisConnectionFactory redisConnectionFactory;

    @Bean(name = "shiroCacheManager")
    public shiroCacheManager shiroCacheManager() {
        RedisCacheConfiguration conf = RedisCacheConfiguration.defaultCacheConfig();
        //shiro配置的缓存管理器是这个,这里是设置登录的过期时间,及其session的过期时间,按秒为单位
        conf = conf.entryTtl(Duration.ofSeconds(300000));
        RedisCacheManager cacheManager = RedisCacheManager
                .builder(redisConnectionFactory)
                .cacheDefaults(conf)
                .build();
        shiroCacheManager shiroCacheManager = new shiroCacheManager(cacheManager);
        return shiroCacheManager;
    }

    @Bean(name = "redisCacheManager")
    public RedisCacheManager redisCacheManager() {
        RedisCacheConfiguration cacheConfig = RedisCacheConfiguration.defaultCacheConfig();
        RedisCacheManager redisCacheManager = RedisCacheManager.builder(redisConnectionFactory)
                .cacheDefaults(cacheConfig)
                .build();
        return redisCacheManager;
    }
}

测试

当我们登录的时候(subject.login),发现redis里面确实把 认证信息,session数据写进去了

shiro缓存配置流程_java_03


不断刷新这个页面,发现压根不会进入loginrealm中的授权这,如果没有配置缓存管理器,那么每次刷新都会走授权

shiro缓存配置流程_java_04

接着我们登出的时候也就是执行下面的代码时候,数据成功移除realm和session数据

Subject subject = SecurityUtils.getSubject();
subject.logout();

shiro缓存配置流程_redis_05

总结

在集成到shiro中的时候,自己编写 CacheManager 实现对Cache的增删改查会出现很多bug(不建议造轮子),本文的代码也就是为了让大家理解 shiro 的几大核心组件以及缓存生效的配置规则而已。


标签:缓存,return,流程,shiroCacheManager,session,redisCacheManager,public,shiro
From: https://blog.51cto.com/u_16414043/9346290

相关文章

  • sringboot整合shiro实现前后端鉴权控制,标签注解速成(包含常见错误的出现,前后端注解标签
    搭建shiro环境1:导入boot项目中要用到的shiro依赖<!--shiro部分--><!--shiro核心源码--><dependency><groupId>org.apache.shiro</groupId><artifactId>shiro-spring</artifactId><version......
  • 正确理解springboot国际化简易运行流程
    看源码可以看出–》大致原理localeResolver国际化视图(默认的就是根据请求头带来的区域信息获取Locale进行国际化)返回的本地解析是根据响应头来决定的)接着按住ctrl点localeresolver可知localeresolver是一个接口于是有了这些我们只需通过继承LocaleResolver来自定义我们自己的Loca......
  • 深入剖析MyBatis缓存机制
    第1章:引言大家好,我是小黑。今天我们要聊的是MyBatis的缓存机制。作为Java开发中经常使用的持久层框架,MyBatis以其灵活性和简便性而广受欢迎。但你知道吗,很多时候,正是因为这些特点,我们需要更深入地理解它的内部工作原理,尤其是缓存机制。这不仅能帮助我们更高效地使用MyBatis,还能......
  • 从零开始:直播电商APP开发全流程解析
    本篇文章,小编将从零开始,全面解析直播电商APP的开发流程,涵盖了关键的技术要点和开发阶段的关键步骤。 第一阶段:需求分析与规划此阶段的关键任务包括:1.用户需求调研2.功能规划3.技术选型第二阶段:设计与原型设计阶段是将需求转化为可执行计划的关键环节。在这一阶段,团队需要完成以下......
  • 视频直播app源码,利用缓存实现连续登录失败后的时间等待
    实现步骤:1、用户在视频直播app源码中发起登录请求2、后台验证是否失败次数过多,账户没有锁定的话就进入下面的步骤;否则直接返回3、验证用户的账号+密码3.1验证成功:删除缓存3.2验证失败:统计最近10分钟时间窗口内的失败次数,如果达到5次则设置锁定缓存,返回图解实......
  • VMware Aria Automation Orchestrator 8.16 - 现代工作流程自动化平台
    VMwareAriaAutomationOrchestrator8.16-现代工作流程自动化平台请访问原文链接:https://sysin.org/blog/vmware-aria-automation-orchestrator/,查看最新版。原创作品,转载请保留出处。作者主页:sysin.org现代工作流程自动化平台VMwareAriaAutomationOrchestratorVMwar......
  • 如何使用CRM实现销售流程自动化?CRM作用解析
    科技在当今时代扮演着重要的角色。在商业领域,我们用很多不同的软件来完成业务、提高效率。销售被认为是一个企业的灵魂。没有销售,企业很难生存。为了使销售更加有效,自动化是每个企业都应该采用的一个重要战略。实现销售过程自动化最简单的方法就是在你的业务中实施CRM软件。CRM可......
  • 记一次缓存失效引发的惨案!
    对于小猫来讲,最近的一段日子是不好过的,纵使听着再有节拍的音乐,也换不起他对生活的热情。由于上一次“幂等事件”躺枪,他已经有几天没有休息好了。他感觉人生到了低谷。当接手这个商城项目之后,他感觉他一直没有好过。他的内心彷徨,在工位上边写着事故报告,边嘀咕着“今年到底是犯了啥......
  • 图像采集和多缓存项目中的若干总结
    遇到的问题:1.图像滚动:原因:没有读出/写入整幅图像导致;2.图像错位:原因:在读出当前帧前,已向fifo里写入了若干数据;(合理的设置hdmi的启动可以解决这个问题);3.图像撕裂:原因:读到了写入区域;缓存多帧数可以解决这个问题;4.缓存后的图像闪动:原因:没有准确的设置启动,导致不合理的地址跳跃;5.6......
  • iMessage群发,iMessage群发软件(流程梳理篇)
    在数字时代,信息传递的速度与准确性显得尤为重要,iMessage作为Apple设备间的通讯工具,具有无可比拟的优势。对于企业或个人而言,开发一款iMessage群发软件具有巨大的商业价值,本文将详细梳理iMessage群发软件的开发流程,并分享一些相关的源代码片段。一、需求分析在开始开发之前,首先......