shiro

org.apache.shiro.web.filter.authc.LogoutFilter is already configured in ShiroWebModule


I'm using Shiro 1.7.1 and Guice 4.2.3, below is the snippet of my POM file,

  <properties>
    <shiro.version>1.7.1</shiro.version>
    <guice.version>4.2.3</guice.version>
  </properties>
  <dependencies>
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-web</artifactId>
      <version>${shiro.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-guice</artifactId>
      <version>${shiro.version}</version>
    </dependency>
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-ehcache</artifactId>
      <version>${shiro.version}</version>
    </dependency>
    <dependency>
      <groupId>com.google.inject</groupId>
      <artifactId>guice</artifactId>
      <version>${guice.version}</version>
    </dependency>
    <dependency>
      <groupId>com.google.inject.extensions</groupId>
      <artifactId>guice-servlet</artifactId>
      <version>${guice.version}</version>
    </dependency>
    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>3.1.0</version>
      <scope>provided</scope>
    </dependency>
    ...
  </dependencies>

I'm customizing Shiro's LogoutFilter by creating a new class,

package com.myshiro.myshiro;


import org.apache.shiro.web.filter.authc.LogoutFilter;

public class MyLogoutFilter extends LogoutFilter {
}

and bind org.apache.shiro.web.filter.authc.LogoutFilter to the above customized MyLogoutFilter,

package com.myshiro.myshiro;

public class MyShiroModule extends ShiroWebModule {

    public MyShiroModule(ServletContext servletContext) {
        super(servletContext);
    }

    protected void configureShiroWeb() {
        try {
            bindRealm().toConstructor(IniRealm.class.getConstructor(Ini.class));
        } catch (NoSuchMethodException e) {
            addError(e);
        }
        bind(org.apache.shiro.web.filter.authc.LogoutFilter.class).to(MyLogoutFilter.class).in(Scopes.SINGLETON);
        addFilterChain("/logout", LOGOUT);
    }
}

and I try to create the Guice injector in the unit test class like this,

public class MyShiroModuleTest {

    @Mock
    private ServletContext servletContext;

    @Test
    public void test() {
        Guice.createInjector(new MyShiroModule(servletContext));
    }
}

and it failed with the following errors,

1) Binding to null instances is not allowed. Use toProvider(Providers.of(null)) if this is your intended behaviour.
  at org.apache.shiro.guice.web.ShiroWebModule.configureShiro(ShiroWebModule.java:136)

2) A binding to org.apache.shiro.web.filter.authc.LogoutFilter was already configured at com.myshiro.myshiro.MyShiroModule.configureShiroWeb(MyShiroModule.java:25).
  at org.apache.shiro.guice.web.ShiroWebModule.setupFilterChainConfigs(ShiroWebModule.java:209)

From the second note above, it explained that the binding to org.apache.shiro.web.filter.authc.LogoutFilter is already configured in both MyShiroModule and ShiroWebModule. Do you have any idea of how to bind to my customized LogoutFilter?

This issue did not happened in Shiro 1.3.x.

My sample project is available here, you can see the error simply when you mvn clean install.


Solution

  • Sounds like your problem is related to Guice 4, and less about Shiro. Instead of re-using the same binding key, define a new one, something like:

    bind(MyLogoutFilter.class).to(MyLogoutFilter.class).in(Scopes.SINGLETON);
    addFilterChain("/logout", Key.get(MyLogoutFilter.class));