Fork me on GitHub

Simple. Java. Security.

Integrating Apache Shiro into Guice based Application

Shiro Guice integration was added in Shiro 1.2. This page covers the ways to integrate Shiro into Guice-based applications using standard Guice conventions and mechanisms. Prior to reading this integration document, you should be a least somewhat familiar with Guice.

Overview

shiro-guice provides three Guice modules that can be included in your application.

Getting Started

The most simple configuration is to extend ShiroModule to install your own Realm.

class MyShiroModule extends ShiroModule {
    protected void configureShiro() {
        try {
            bindRealm().toConstructor(IniRealm.class.getConstructor(Ini.class));
        } catch (NoSuchMethodException e) {
            addError(e);
        }
    }

    @Provides
    Ini loadShiroIni() {
        return Ini.fromResourcePath("classpath:shiro.ini");
    }
}

In this case, user and role configuration would go in the shiro.ini file.

shiro.ini usage in Guice

It is important to note that, in this above configuration, only the `users` and `roles` sections from the ini file are used.

Then, the module is used to create a Guice injector, and the injector is used to obtain a SecurityManager. The following example serves the same purpose as the first three lines in the Quickstart example.

Injector injector = Guice.createInjector(new MyShiroModule());
SecurityManager securityManager = injector.getInstance(SecurityManager.class);
SecurityUtils.setSecurityManager(securityManager);

AOP

Shiro includes several annotations and method interceptors useful for performing authorization via AOP. It also provides a simple API for writing Shiro-specific method interceptors. shiro-guice supports this with the ShiroAopModule.

To use it, simply instantiate and install the module alongside your application module and your ShiroModule.

Injector injector = Guice.createInjector(new MyShiroModule(), new ShiroAopModule(), new MyApplicationModule());

If you have written custom interceptors that conform to Shiro’s api, you may find it useful to extend the ShiroAopModule.

class MyShiroAopModule extends ShiroAopModule {
    protected void configureInterceptors(AnnotationResolver resolver)
    {
        bindShiroInterceptor(new MyCustomAnnotationMethodInterceptor(resolver));
    }
}

Web

shiro-guice’s web integration is designed to integrate Shiro and its filter paradigm with Guice’s servlet module. If you are using Shiro in a web environment, and using Guice’s servlet module, then you should extend ShiroWebModule rather than ShiroModule. Your web.xml should be setup exactly as Guice’s servlet module recommends.

class MyShiroWebModule extends ShiroWebModule {
    MyShiroWebModule(ServletContext sc) {
        super(sc);
    }

    protected void configureShiroWeb() {
        try {
            bindRealm().toConstructor(IniRealm.class.getConstructor(Ini.class));
        } catch (NoSuchMethodException e) {
            addError(e);
        }

        addFilterChain("/public/**", ANON);
        addFilterChain("/stuff/allowed/**", AUTHC_BASIC, config(PERMS, "yes"));
        addFilterChain("/stuff/forbidden/**", AUTHC_BASIC, config(PERMS, "no"));
        addFilterChain("/**", AUTHC_BASIC);
    }

    @Provides
    Ini loadShiroIni() {
        return Ini.fromResourcePath("classpath:shiro.ini");
    }
}

In the previous code, we have bound an IniRealm and setup four filter chains. These chains would be equivalent to the following ini configuration.

[urls]
/public/** = anon
/stuff/allowed/** = authcBasic, perms["yes"]
/stuff/forbidden/** = authcBasic, perms["no"]
/** = authcBasic

In shiro-guice, the filter names are Guice keys. All of the default Shiro filters are available as constants, but you are not limited to those. In order to use a custom filter in a filter chain, you would do

Key customFilter = Key.get(MyCustomFilter.class);

addFilterChain("/custom/**", customFilter);

We still have to tell guice-servlets about our Shiro filter. Since the ShiroWebModule is private, and guice-servlets does not give us a way to expose a filter mapping, we have to bind it manually.

ShiroWebModule.guiceFilterModule()

Or, from within an application module,

ShiroWebModule.bindGuiceFilter(binder())

Properties

A number of Shiro classes expose configuration parameters via setter methods. shiro-guice will inject these if it finds a binding for @Named("shiro.{propName}"). For instance, to set the session timeout, you could do the following.

bindConstant().annotatedWith(Names.named("shiro.globalSessionTimeout")).to(30000L);

If this paradigm doesn’t work for you, you may also consider using a provider to instantiate the object and invoking the setters directly.

Injection of Shiro Objects

shiro-guice uses a Guice TypeListener to perform injection on native Shiro classes (any class in a subdirectory of org.apache.shiro but not org.apache.shiro.guice). However, Guice only considers explicitly bound types as candidates for TypeListeners, so if you have a Shiro object that you want injected, you have to declare it explicitly. For instance, to set the CredentialsMatcher for a realm, we would need to add the following bindings:

bind(CredentialsMatcher.class).to(HashedCredentialsMatcher.class);
bind(HashedCredentialsMatcher.class);
bindConstant().annotatedWith(Names.named("shiro.hashAlgorithmName")).to(Md5Hash.ALGORITHM_NAME);

Lend a hand with documentation

While we hope this documentation helps you with the work you're doing with Apache Shiro, the community is improving and expanding the documentation all the time. If you'd like to help the Shiro project, please consider correcting, expanding, or adding documentation where you see a need. Every little bit of help you provide expands the community and in turn improves Shiro.

The easiest way to contribute your documentation is to submit a pull-request by clicking on the Edit link below, send it to the User Forum or the User Mailing List.