开发问题:记配置 shiro 排除路径失效的问题

本文发布于 2024年08月29日,阅读 18 次,点赞 0 次,归类于 开发问题记录

by emanjusaka from https://www.emanjusaka.top/2024/08/record-shiro-exclude-path-hashmap 彼岸花开可奈何

本文为原创文章,可能会更新知识点以及修正文中的一些错误,全文转载请保留原文地址,避免未即时修正的错误误导。

一、问题背景

上周一个使用 shiro 的项目在yaml 配置文件中新增了一条排除路径(即不需要进行安全验证的路径)的时候,发现不但新配置的路径不生效之前生效的排除路径也有部分失效了。而且颇为神奇的是在 yaml 中配置 5 条以上的排除路径就会产生问题,不超过 5 条以上问题未出现。回顾了下代码并没有任何限制数量的东西。

二、关键代码

在这里展示部分关键代码,相关不便于展示部分已隐藏或修改。

yaml 配置文件

 security:
   cloud:
     onlyFetchByGateway: true
     excludePath:
       - /logout/**
       - /sso/**
       - /getSecretKey
       - /checkLogin/**
       - /getSetting/**
       - /ukey/**

正如上面所示最后一条路径是新增的,增加完出现问题。

shiro 配置代码

     @Bean
     public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager,
                                                          Properties properties) {
         ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
         Map<String, Filter> filters = shiroFilterFactoryBean.getFilters();
         filters.put("authc", new CustomUserFilter(redisTemplate,cloudSecurityProperties));
         shiroFilterFactoryBean.setSecurityManager(securityManager);
         Map<String, String> map = new HashMap<>();
         //登出
         map.put("/logout", "logout");
         map.put("/oauthxxx/**", "anon");
         map.put("/dataxx/**", "anon");
         map.put("/auth/callxxx/**", "anon");
         map.put("/auth/getxxx/**", "anon");
         map.put("/party/createxxx/**", "anon");
         List<String> excludePath = properties.getExcludePath();
         if (CollUtil.isNotEmpty(excludePath)) {
             for (String path : excludePath) {
                 map.put(path, "anon");
             }
         }
         //对所有用户认证
         map.put("/**", "authc");
         shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
         return shiroFilterFactoryBean;
     }

三、问题探究

上面展示了部分关键代码,初看的时候并没有发现什么问题。当看到map.put("/**", "authc");这行代码突然意识到这个要放到最后一个的,否则在它后面的排除路径是无效的。再去看这个 map 发现使用的是 HashMap,顿时灵光一闪HashMap 是无序的会不会是它导致的问题出现。马上修改代码把 HashMap 改为有序的 LinkedHashMap,经过实际验证发现问题解决。

果然一些基础知识的掌握一定要牢靠,否则会导致问题解决花费很长时间。如果不能第一时间就意识到 HashMap 是无序的,那这个问题可能会花费更长的时间,甚至于都不能解决。

四、深入研究

秉着有任何疑问都要打破砂锅问到底的态度,为啥在 yaml 中配置 5 条以上的排除路径就会产生问题,不超过 5 条以上问题未出现呢?

我们都知道 HashMap 的初始默认容量是 16,它的默认扩容因子为 0.75,当容量达到 12(16 x 0.75)时,HashMap 会进行扩容。扩容过程涉及创建一个新的内部数组,其大小通常是原始大小的两倍,并重新分布(或称为“再哈希”)所有现有的键值对到这个新数组中。

上面代码map 已经有了 7 条数据,而 yaml 配置文件中的排除路径超过 5 个时,它们加在一起就会超过 12 触发扩容机制。重新分布后这时顺序可能就会不在一样。而map.put("/**", "authc");跑到了前面的时候,在它后面的排除路径就会全部失效。

yiyan

在技术的星河中遨游,我们互为引路星辰,共同追逐成长的光芒。愿本文的洞见能触动您的思绪,若有所共鸣,请以点赞之手,轻抚赞同的弦。

原文地址: https://www.emanjusaka.top/2024/08/record-shiro-exclude-path-hashmap

微信公众号:emanjusaka的编程栈