| = 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("shiro.{propName}")`. 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 /> |
| ++++ |