添加自定义过滤器Apache Shiro + Spring Boot

时间:2018-07-27 06:31:49

标签: java spring spring-mvc spring-boot shiro

我试图将基于Spring MVC xml的项目配置重构为基于Spring Boot java的配置。如下设置shiro配置:

@Configuration
public class ShiroConfig {

    @Bean
    public Realm realm() {
        JdbcRealm myRealm = new JdbcRealm();
        myRealm.setCredentialsMatcher(sha256Matcher());
        myRealm.setPermissionsLookupEnabled(true);
        myRealm.setSaltStyle(JdbcRealm.SaltStyle.COLUMN);
        return myRealm;
    }

    @Bean
    public HashedCredentialsMatcher sha256Matcher() {
        HashedCredentialsMatcher sha256Matcher = new HashedCredentialsMatcher();
        sha256Matcher.setHashAlgorithmName("SHA-256");
        return sha256Matcher;
    }

    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    @Bean
    public CacheManager cacheManager() {
        return new MemoryConstrainedCacheManager();
    }       

    @Bean
    public Filter jwtv() {
        return new JWTVerifyingFilter();
    }

    @Bean
    public Filter ljwtv() {
        return new LimitedAccessJWTVerifyingFilter();
    }

    @Bean
    public Filter logout() {
        LogoutFilter logoutFilter = new LogoutFilter();
        logoutFilter.setRedirectUrl("/login.jsp");
        return logoutFilter;
    }

    @Bean
    public ShiroFilterChainDefinition shiroFilterChainDefinition() {
        DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();

        chainDefinition.addPathDefinition("/login", "authc");
        chainDefinition.addPathDefinition("/logout", "logout");
        chainDefinition.addPathDefinition("/my/test/**", "anon");
        chainDefinition.addPathDefinition("/my/xyz/**/abc", "ljwtv");            chainDefinition.addPathDefinition("/my/xyz/**/mno", "ljwtv");
        chainDefinition.addPathDefinition("/my/**", "jwtv");

        return chainDefinition;
    }

}

我遇到以下错误:

  

启动Tomcat上下文时出错。例外:   org.springframework.beans.factory.BeanCreationException。信息:   创建名称为'filterShiroFilterRegistrationBean'的bean时出错   在类路径资源中定义   [org / apache / shiro / spring / config / web / autoconfigure / ShiroWebFilterConfiguration.class]:   通过工厂方法实例化Bean失败;嵌套异常为   org.springframework.beans.BeanInstantiationException:失败   实例化   [org.springframework.boot.web.servlet.FilterRegistrationBean]:工厂   方法'filterShiroFilterRegistrationBean'抛出异常;嵌套的   异常是org.springframework.beans.factory.BeanCreationException:   创建名称为“ shiroFilterFactoryBean”的bean时出错:FactoryBean   在对象创建时抛出异常;嵌套异常为   java.lang.IllegalArgumentException:没有名称过滤器   'jwtv'应用于可用过滤器池中的链[/ my / **]。   确保具有该名称/路径的过滤器已首先在   addFilter方法。

自定义文件管理器JWTVerifyingFilter是扩展@Component的{​​{1}}。不知道我缺少什么,所有这些都可以与xml配置一起使用。请帮忙。

1 个答案:

答案 0 :(得分:1)

看起来,Boot集成没有从Spring Context添加过滤器。 (预启动/ Java配置,通常是用XML定义的,这不是问题)。

不过,解决方法非常简单,只需添加此bean def:

@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Value("#{ @environment['shiro.loginUrl'] ?: '/login.jsp' }") String loginUrl,
                                                     @Value("#{ @environment['shiro.successUrl'] ?: '/' }") String successUrl,
                                                     @Value("#{ @environment['shiro.unauthorizedUrl'] ?: null }") String unauthorizedUrl,
                                                     SecurityManager securityManager,
                                                     ShiroFilterChainDefinition shiroFilterChainDefinition,
                                                     Map<String, Filter> filterMap) {

    ShiroFilterFactoryBean filterFactoryBean = new ShiroFilterFactoryBean();

    filterFactoryBean.setLoginUrl(loginUrl);
    filterFactoryBean.setSuccessUrl(successUrl);
    filterFactoryBean.setUnauthorizedUrl(unauthorizedUrl);

    filterFactoryBean.setSecurityManager(securityManager);
    filterFactoryBean.setFilterChainDefinitionMap(shiroFilterChainDefinition.getFilterChainMap());
    filterFactoryBean.setFilters(filterMap);

    return filterFactoryBean;
}

我还创建了一个PR,将其添加回Shiro(一旦我们添加了测试)。

更新:

我认为您的JSP处理配置不正确,但是重定向问题是由注销过滤器的定义引起的。该过滤器将在每个请求上得到处理(到Spring为止)。您需要改用映射到路径的FitlerRegistrationBean

@Bean
public FilterRegistrationBean logout() {
    FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
    LogoutFilter logoutFilter = new LogoutFilter();
    logoutFilter.setRedirectUrl("/login.jsp");
    filterRegistrationBean.setFilter(logoutFilter);
    filterRegistrationBean.addUrlPatterns("/logout.htm");
    return filterRegistrationBean;
}

更新:自动过滤器注册会带来更多乐趣

我认为这两个问题的根源是Spring会自动添加过滤器,然后Shiro也会使用它们。

如果定义过滤器bean,并使用FilterRegistrationBean禁用它,Spring不会自动添加过滤器(IIRC)。这意味着Shiro可以管理过滤器链(这就是我们想要发生的事情)

使用以下代码段: ```     @豆角,扁豆     公共过滤器jwtv(){         返回新的JWTVerifyingFilter();     }

@Bean
public FilterRegistrationBean jwtvFilterRegBean() {
    FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
    filterRegistrationBean.setFilter(jwtv());
    filterRegistrationBean.setEnabled(false);
    return filterRegistrationBean;
}

```

点击/时,我可以触发您的过滤器:

HTTP/1.1 403 Content-Length: 0 Date: Thu, 27 Sep 2018 20:01:26 GMT message: NO TOKEN!

但是在击中/test时不是。

对于任何尝试实现自定义过滤器(例如JWT令牌化授权)的人: Sample Project