blob: 3d207e29cd90f748268d71f8e343b8eea1eda054 [file] [log] [blame]
= Integrating Apache Shiro into Guice based Application
:jbake-date: 2010-03-18 00:00:00
:jbake-type: page
:jbake-status: published
:jbake-tags: documentation, integration, guice
:idprefix:
:icons: font
:toc:
Shiro https://github.com/google/guice[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.
* ShiroModule
** Provides basic integration for setting up the `SecurityManager`, any `Realms`, and any other Shiro configuration.
** This module is used by extending it and adding your own custom configuration.
* ShiroWebModule
** Extension of `ShiroModule` that sets up the web environment and also allows for filter chain configuration. This uses the https://github.com/google/guice/wiki/ServletModule[Guice Servlet Module] to configure the filters, and so requires that to be setup.
** Like the `ShiroModule`, this module is used by extending it and adding your own custom configuration.
* ShiroAopModule
** Uses https://github.com/google/guice/wiki/AOP[Guice AOP] to implement the Shiro AOP annotations. This module is primarily concerned with adapting Shiro `AnnotationMethodInterceptors` to the Guice method interceptor model.
** This module is typically used by simply installing it. However, if you have your own `AnnotationMethodInterceptors` written for Shiro, they can be easily incorporated by extending it.
== Getting Started
First, include the shiro-guice dependency in your project:
++++
<@dependencies.dependencies anchorId="cli" deps=[{'g':'org.apache.shiro', 'a':'shiro-guice', "v":"${versions.latestRelease}"}] />
++++
The most simple configuration is to extend `ShiroModule` to install your own `Realm`.
[source,java]
----
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.
[CAUTION]
.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 link:/10-minute-tutorial.html#quickstart_java[Quickstart] example.
[source,java]
----
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`.
[source,java]
----
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`.
[source,java]
----
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.
[source,java]
----
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.
[source,ini]
----
[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
[source,java]
----
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.
[source,java]
----
ShiroWebModule.guiceFilterModule()
----
Or, from within an application module,
[source,java]
----
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(&quot;shiro.{propName}&quot;)`. For instance, to set the session timeout, you could do the following.
[source,java]
----
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:
[source,java]
----
bind(CredentialsMatcher.class).to(HashedCredentialsMatcher.class);
bind(HashedCredentialsMatcher.class);
bindConstant().annotatedWith(Names.named("shiro.hashAlgorithmName")).to(Md5Hash.ALGORITHM_NAME);
----
++++
<@lendahand.lendahand />
++++