(springboot)shiro安全框架自定义过滤器出现的几个疑难杂症解决方案

问题一:多次重复重定向问题(匹配多个过滤器链重复调用其对应过滤器)

问题二:shiro认证时Realm会执行两次

在使用springboot框架整合shiro安全认证框架时踩了很多坑,每次出问题网上都找不到其中的解决方案,这里贴两个我遇到的坑,以及其解决方案给大家,希望大家可以少走弯路。

问题一场景:

		// 自定义拦截器
		Map<String, Filter> customisedFilter = new HashMap<>();
		customisedFilter.put("url", new CustomRolesAuthorizationFilter());

		// 配置映射关系
		filterChainDefinitionMap.put("/login", "anon");
		filterChainDefinitionMap.put("/index", "anon");
		filterChainDefinitionMap.put("/unauthorized", "anon");
		filterChainDefinitionMap.put("/doLogout", "logout");
		filterChainDefinitionMap.put("/**", "url");
		shiroFilterFactoryBean.setFilters(customisedFilter);
		shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);

当我访问/login时,会进入anon过滤器 。但是问题出在,他还会额外继续执行url(自定义过滤器),在自定义过滤器中的逻辑是用户没有登录就重定向到/login这个url去,然后又进入anon过滤器,又执行url过滤器,又进行重定向,循环往复造成多次重定向。

问题一解决过程:

翻阅了一些shiro的资料,了解了一下其中过滤器的机制,shiro会对Servlet容器里的FilterChain进行代理,Shiro会通过一个代理类ProxiedFilterChain对Servlet对其进行代理,其中会先进行Shiro中用户自己配置的拦截器配置映射的关系,即先走映射关系中匹配到的url对应的过滤器,然后会去执行Servlet中的FilterChain进行Filter链的执行。

如果有看过底层源码,就会看到一个originalChain这个名词,它就是Servlet保存的FilterChain。也就是说,每次请求都将会先走Shiro的过滤器链,然后再走Servlet的过滤器链。

这里我是SpringBoot框架,可以看到控制台在项目启动时自动配置characterEncodingFilter、requestContextFilter等等一些默认过滤器,把它加入一个叫FilterRegistrationBean中,作为一个过滤器链。可以看到红框中,这两个是我自己自定义的过滤器,我将其配置到Shiro中作为Shiro过滤器链使用,但没想到SpringBoot自动把这两个过滤器配置到了FilterRegistrationBean中,并且路径为/*,这也就能理解为什么上面会匹配到anon过滤器之后还会往下执行到我们的自定义过滤器了。

这是我两个自定义过滤器的配置Bean,其中过滤器实现了PathMatchingFilter接口,我不知道是不是因为这个,还是什么奇怪的原因才会把它加载到FilterRegistrationBean中,如果有知道为什么的可以在底下评论告知我一下,至今还是对此摸不着头脑。

问题一解决方案:

最后我把这两个Bean注释掉了,在配置Shiro中我直接new出来,不作为Bean交给IOC管理了,这样就解决了问题,Shiro就不会调用额外的自定义过滤器了。

问题二解决过程:

当时因为我需要动态配置映射关系,会从数据库中读取需要映射的url与需要拦截的角色与权限,过滤器链有可能同一个URL匹配多个过滤器(例如permission过滤器和roles过滤器,角色与权限双验证效果),所以我就自定义了PathMatchingFilterChainResolver,并重写了getChain方法,这个方法是用来匹配返回即将调用的过滤器的,在里面我的逻辑是匹配所有匹配到的URL,把所有对应能匹配到的过滤器全部执行,但错误在,我在最底下写了一个匹配规则 /** 匹配authc,逻辑是除了需要权限验证、或是设置了anon、logout过滤器以外的url都要进行登录才可以访问,这就造成了在进行登录的时候,访问一次登录方法,又会去匹配那个/** 继续走一次身份验证,而走身份验证 subject.login 的底层是会走Realm,这就造成了走两次Realm。

问题二解决方案:

造成这种问题很大可能是PathMatchingFilterChainResolver中的getChain逻辑没有写好,ufl映射关系配置不科学造成。

下面贴一个我的getChian方法。

    public FilterChain getChain(ServletRequest request, ServletResponse response, FilterChain originalChain) {
        FilterChainManager filterChainManager = getFilterChainManager();
        if (!filterChainManager.hasChains()) {
            return null;
        }

        String requestURI = getPathWithinApplication(request);
        
        //要执行的过滤器集合
        List<String> chainNames = new ArrayList<String>();

        //获取全部的拦截url
        Set<String> chain = filterChainManager.getChainNames();

        for (String pathPattern : chain){
            // 匹配所有匹配到的url,装入chainNames作为即将要执行的过滤器集合
            if (pathMatches(pathPattern, requestURI)) {
                chainNames.add(pathPattern);
            }
        }
        //拦截器链的最后一个Url,因为它匹配全部的url,这里不与其他拦截器冲突,剔除/**url的匹配
        Object lastUrl = "/**";
        chainNames.remove(lastUrl);
        //没有匹配到url
        if(chainNames.size() == 0) {
            //为了不与其他拦截器冲突,在全部url都不匹配的情况下才匹配/**
            chainNames.add("/**");
        }
        return customDefaultFilterChainManager.proxy(originalChain, chainNames);
    }

基本思路就是匹配除了/**的所有过滤器路径,如果能匹配到,则执行匹配到的过滤器集合,如果一个都没匹配到,才走最后的身份验证。

要了解底层Shiro是怎么进行身份验证,这样出了问题就能通过Debug进行排错,如果项目中需要深度整合Shiro,改写很多Shiro的验证逻辑,需要了解Shiro底层原理,如FilterChainResolver(处理匹配规则)、FilterChainManager(处理匹配到的过滤器链)、PathMatchingFilter(自定义过滤器)、AuthorizingRealm(获取认证相关数据源的地方)、CredentialsMatcher(自定义登录认证逻辑)等等的原理,才能灵活运用Shiro框架。有空写一篇动态URL配置,动态双拦截角色权限的Shiro配置,和与SSO单点登录的WebService服务接口整合实现自定义的登录与权限的逻辑。

  • 9
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 在 Spring Boot 中使用 shiro 配置自定义过滤器需要以下几个步骤: 1. 引入 shiro-spring-boot-starter 依赖: ``` <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-starter</artifactId> <version>1.7.1</version> </dependency> ``` 2. 创建自定义过滤器: ``` public class CustomFilter extends AccessControlFilter { @Override protected boolean isAccessAllowed(ServletRequest servletRequest, ServletResponse servletResponse, Object o) throws Exception { // 在这里实现自定义的过滤逻辑,返回 true 表示通过过滤器,返回 false 表示未通过过滤器 return true; } @Override protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception { // 如果 isAccessAllowed 返回 false,则会进入到这里,可以在这里处理未通过过滤器的情况 return false; } } ``` 3. 配置 shiro 的 FilterChainDefinition: ``` @Bean public ShiroFilterChainDefinition shiroFilterChainDefinition() { DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition(); // 添加自定义过滤器,其中 key 是过滤器名称,value 是该过滤器对应的路径 chainDefinition.addPathDefinition("/custom/**", "custom"); return chainDefinition; } ``` 4. 配置自定义过滤器: ``` @Bean("custom") public CustomFilter customFilter() { return new CustomFilter(); } ``` 5. 配置 shiro 的注解支持: ``` @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager) { AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(securityManager); return advisor; } ``` 完成以上步骤后,就可以在 Spring Boot 中使用 shiro 配置自定义过滤器了。 ### 回答2: 在 Spring Boot 中使用 Shiro 配置自定义过滤器分为三个步骤。 第一步,创建自定义过滤器类。可以通过实现 Shiro 的 Filter 接口来创建自定义过滤器。在自定义过滤器中需要实现过滤规则,并对请求进行相应的处理。 第二步,配置 Shiro 过滤器链。在 Spring Boot 的配置类中,通过创建 ShiroFilterFactoryBean 对象来配置 Shiro过滤器链。可以使用 Shiro 的 FilterChainDefinitionMap 对象来配置过滤器链,然后将该对象设置ShiroFilterFactoryBean。 第三步,启用 Shiro 过滤器。在 Spring Boot 的配置类中,通过创建 DefaultFilterChainManager 对象,并将该对象设置ShiroFilterFactoryBean,启用自定义过滤器。 有了以上三步,就可以在 Spring Boot 中使用 Shiro 配置自定义过滤器了。可以通过在自定义过滤器中实现过滤规则来对请求进行拦截或处理,然后在 Shiro 过滤器链中配置该过滤器,最后启用该过滤器。这样就可以实现对请求的自定义过滤器处理。 值得注意的是,在使用 Shiro 进行自定义过滤器配置时,需要保证 Shiro 的配置文件中已经进行了相应的配置,包括认证和授权等相关配置。只有在正确配置的前提下,才能正确使用 Shiro 进行自定义过滤器的配置。 ### 回答3: 在Spring Boot中使用Shiro配置自定义过滤器通常需要以下几个步骤: 1. 引入Shiro和Spring Boot依赖。在pom.xml文件中添加Shiro和Spring Boot Starter依赖: ``` <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-starter</artifactId> <version>1.7.1</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> ``` 2. 创建自定义过滤器类。可以通过实现`javax.servlet.Filter`接口或者继承`org.apache.shiro.web.servlet.OncePerRequestFilter`类来创建自定义过滤器。例如,创建一个名为`CustomFilter`的自定义过滤器类: ``` public class CustomFilter extends OncePerRequestFilter { @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { // 过滤器逻辑处理 // ... filterChain.doFilter(request, response); } } ``` 3. 在Shiro配置类中注册自定义过滤器。创建一个Shiro配置类,并使用`@Configuration`注解标记为配置类。通过`@Bean`注解将自定义过滤器注册到Shiro过滤器链中。例如,在配置类`ShiroConfig`中注册`CustomFilter`: ``` @Configuration public class ShiroConfig { @Bean public FilterRegistrationBean<CustomFilter> customFilterRegistrationBean() { FilterRegistrationBean<CustomFilter> registrationBean = new FilterRegistrationBean<>(); registrationBean.setFilter(new CustomFilter()); registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE); // 过滤器执行顺序 registrationBean.addUrlPatterns("/*"); // 过滤器路径 return registrationBean; } } ``` 4. 配置Shiro的过滤规则。在Shiro配置文件中,可以设置自定义过滤器的拦截规则。例如,在`shiro.ini`配置文件中,设置自定义过滤器的拦截规则: ``` [urls] /** = customFilter // 对所有请求都使用自定义过滤器 ``` 通过以上步骤,在Spring Boot中使用Shiro配置自定义过滤器就可以实现对特定请求的拦截和处理。在`CustomFilter`类的`doFilterInternal`方法中编写自定义过滤器逻辑,例如鉴权、权限验证等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值