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

Adding Custom filter Apache Shiro + Spring Boot

我正在尝试将基于 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;
    }

}

我遇到以下错误:

Error starting Tomcat context. Exception: org.springframework.beans.factory.BeanCreationException. Message: Error creating bean with name 'filterShiroFilterRegistrationBean' defined in class path resource [org/apache/shiro/spring/config/web/autoconfigure/ShiroWebFilterConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [org.springframework.boot.web.servlet.FilterRegistrationBean]: Factory method 'filterShiroFilterRegistrationBean' threw exception; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'shiroFilterFactoryBean': FactoryBean threw exception on object creation; nested exception is java.lang.IllegalArgumentException: There is no filter with name 'jwtv' to apply to chain [/my/**] in the pool of available Filters. Ensure a filter with that name/path has first been registered with the addFilter method(s).

自定义文件管理器 JWTVerifyingFilter 是一个扩展 org.apache.shiro.web.filter.AccessControlFilter@Component。不知道我错过了什么,这一切都适用于 xml 配置。请帮忙。

看起来 Boot 集成没有从 Spring 上下文中添加过滤器。 (预引导/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 可以管理过滤器链(这是我们想要发生的)

使用以下代码段: ``` @豆 public 过滤器 jwtv() { return 新的 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