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

Posted

技术标签:

【中文标题】添加自定义过滤器 Apache Shiro + Spring Boot【英文标题】:Adding Custom filter Apache Shiro + Spring Boot 【发布时间】:2019-01-04 05:28:35 【问题描述】:

我正在尝试将基于 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 是一个扩展org.apache.shiro.web.filter.AccessControlFilter@Component。不知道我错过了什么,这一切都适用于 xml 配置。请帮忙。

【问题讨论】:

你能在 GitHub(或其他地方)上整理一个示例项目,我会尝试看看 @BrianDemers github.com/bibekhadka/demo 在这里。感谢您的宝贵时间。 【参考方案1】:

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

使用以下sn-p: ``` @豆角,扁豆 公共过滤器 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

【讨论】:

嗨@Brian,我尝试按照建议添加bean,这消除了运行时异常,但我还没有得到想要的输出。我无法预测任何 api 端点的行为。每个端点似乎都需要身份验证,因为我被重定向到登录 url。浏览器还说重定向太多。 'anon' 似乎对端点没有任何作用,奇怪的是,一些端点正在通过我的自定义实现进行过滤。我越来越焦虑了。请通过设置查看端点行为。 您的 loginUrl 是 /login.jsp 还是 /login?看起来您上面的示例同时使用了两者,重定向循环将您发送到哪里?这应该有助于缩小范围 仍然无法解决这个问题:( 将建议的更改推送到您的 GH 项目中,我会尝试再看看 嗨@Brian,我已经推送了建议的更改。请看一看。

以上是关于添加自定义过滤器 Apache Shiro + Spring Boot的主要内容,如果未能解决你的问题,请参考以下文章

shiro过滤器解释类

带你深入使用shiro,自定义token过滤器

带你深入使用shiro,自定义token过滤器

带你深入使用shiro,自定义token过滤器

带你深入使用shiro,自定义token过滤器

shiro自定义过滤器冲突弹簧过滤器