blob: 948e7c213aeb12e185c343e7d0cfe86c1a61d545 [file] [log] [blame]
= Integrating Apache Shiro into Spring-based Applications
:jbake-date: 2010-03-18 00:00:00
:jbake-type: page
:jbake-status: published
:jbake-tags: documentation, manual, spring
:idprefix:
:toc:
This page covers the ways to integrate Shiro into link:https://spring.io[Spring]-based applications.
== Standalone Applications
Include the Shiro Spring dependency in you application classpath (we recomend using a tool such as Apache Maven or Gradle to manage this).
++++
<@dependencies.dependencies anchorId="cli" deps=[{'g':'org.apache.shiro', 'a':'shiro-spring', "v":"${versions.latestRelease}"},{"g":'org.springframework', "a":'spring-context', "v":'${r"${spring.version}"}'}] />
++++
Import the Shiro Spring configurations:
[source,java]
----
@Configuration
@Import({ShiroBeanConfiguration.class,
ShiroConfiguration.class,
ShiroAnnotationProcessorConfiguration.class})
public class CliAppConfig {
...
}
----
The above configurations do the following:
[width="100%",cols="55%,45%",options="header",]
|===
|Configuration Class |Description
|org.apache.shiro.spring.config.ShiroBeanConfiguration
|Configures Shiros lifecycle and events
|org.apache.shiro.spring.config.ShiroConfiguration
|Configures Shiro Beans (SecurityManager, SessionManager, etc)
|org.apache.shiro.spring.config.ShiroAnnotationProcessorConfiguration
|Enables Shiros annotation processing
|===
The only thing that is left is to configure a link:realm.html[realm]:
[source,java]
----
@Bean
public Realm realm() {
...
}
----
The easiest way to setup Shiro, so that all SecurityUtils.* methods work in all cases, is to make the `SecurityManager` bean a static singleton.
DO NOT do this in web applications - see the link:#web_applications[Web Applications] section below instead.
[source,java]
----
@Autowired
private SecurityManager securityManager;
@PostConstruct
private void initStaticSecurityManager() {
SecurityUtils.setSecurityManager(securityManager);
}
----
That is it, now you can get the current `Subject` using:
[source,java]
----
SecurityUtils.getSubject();
----
You can see a full example in our link:https://github.com/apache/shiro/tree/main/samples/spring[samples on Github].
[#web_applications]
== Web Applications
Shiro has first-class support for Spring web applications. In a web application, all Shiro-accessible web requests must go through a main Shiro Filter. This filter itself is extremely powerful, allowing for ad-hoc custom filter chains to be executed based on any URL path expression.
Include the Shiro Spring web dependencies in you application classpath (we recomend using a tool such as Apache Maven or Gradle to manage this).
++++
<@dependencies.dependencies anchorId="web" deps=[{"g":'org.apache.shiro', "a":'shiro-spring', "v":"${versions.latestRelease}"}, {"g":'org.apache.shiro', "a":'shiro-web', "v":"${versions.latestRelease}"},{"g":'org.springframework', "a":'spring-webmvc', "v":'${r"${spring.version}"}'}] />
++++
Import the Shiro Spring configurations:
[source,java]
----
@Configuration
@Import({ShiroBeanConfiguration.class,
ShiroAnnotationProcessorConfiguration.class,
ShiroWebConfiguration.class,
ShiroWebFilterConfiguration.class,
ShiroRequestMappingConfig.class})
public class ApplicationConfig {
...
}
----
The above configurations do the following:
[width="100%",cols="55%,45%",options="header",]
|===
|Configuration Class |Description
|org.apache.shiro.spring.config.ShiroBeanConfiguration
|Configures Shiros lifecycle and events
|org.apache.shiro.spring.config.ShiroAnnotationProcessorConfiguration
|Enables Shiros annotation processing
|org.apache.shiro.spring.web.config.ShiroWebConfiguration
|Configures Shiro Beans for web usage (SecurityManager, SessionManager, etc)
|org.apache.shiro.spring.web.config.ShiroWebFilterConfiguration
|Configures Shiros web filter
|org.apache.shiro.spring.web.config.ShiroRequestMappingConfig
|Configures Spring with Shiros `UrlPathHelper` implementation to ensure URLs are processed the same both frameworks
|===
Provide a Realm implementation:
[source,java]
----
@Bean
public Realm realm() {
...
}
----
And finally a `ShiroFilterChainDefinition` which will map any application specific paths to a given filter, in order to allow different paths different levels of access.
[source,java]
----
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition() {
DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
// logged in users with the 'admin' role
chainDefinition.addPathDefinition("/admin/**", "authc, roles[admin]");
// logged in users with the 'document:read' permission
chainDefinition.addPathDefinition("/docs/**", "authc, perms[document:read]");
// all other paths require a logged in user
chainDefinition.addPathDefinition("/**", "authc");
return chainDefinition;
}
----
If you are using Shiro's annotations see the link:#annotations_and_web_applications[annotation] section below.
You can see a full example in our link:https://github.com/apache/shiro/tree/main/samples/spring-mvc[samples on Github].
== Enabling Shiro Annotations
In both standalone and web applications, you might want to use Shiro's Annotations for security checks (for example, `@RequiresRoles`, `@RequiresPermissions`, etc.) These annotations are enabled by importing the `ShiroAnnotationProcessorConfiguration` Spring configuration in both sections above.
Simply annotate your methods in order to use them:
[source,java]
----
@RequiresPermissions("document:read")
public void readDocument() {
...
}
----
=== Annotations and Web Applications
Shiro annotations are fully supported for use in `@Controller` classes, for example:
[source,java]
----
@Controller
public class AccountInfoController {
@RequiresRoles("admin")
@RequestMapping("/admin/config")
public String adminConfig(Model model) {
return "view";
}
}
----
A `ShiroFilterChainDefinition` bean with at least one definition is still required for this to work, either configure all paths to be accessable via the `anon` filter or a filter in 'permissive' mode, for example: `authcBasic[permissive]`.
[source,java]
----
@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition() {
DefaultShiroFilterChainDefinition chainDefinition = new DefaultShiroFilterChainDefinition();
chainDefinition.addPathDefinition("/**", "anon"); // all paths are managed via annotations
// or allow basic authentication, but NOT require it.
// chainDefinition.addPathDefinition("/**", "authcBasic[permissive]");
return chainDefinition;
}
----
== Caching
Enabling caching is as simple as providing a link:https://shiro.apache.org/caching.html[CacheManager] bean:
[source,java]
----
@Bean
protected CacheManager cacheManager() {
return new MemoryConstrainedCacheManager();
}
----
== Configuration Properties
[width="100%",cols="36%,14%,40%",options="header",]
|===
|Key |Default Value |Description
|shiro.sessionManager.deleteInvalidSessions |`true` |Remove invalid
session from session storage
|shiro.sessionManager.sessionIdCookieEnabled |`true` |Enable session ID
to cookie, for session tracking
|shiro.sessionManager.sessionIdUrlRewritingEnabled |`true` |Enable
session URL rewriting support
|shiro.userNativeSessionManager |`false` |If enabled Shiro will manage
the HTTP sessions instead of the container
|shiro.sessionManager.cookie.name |`JSESSIONID` |Session cookie name
|shiro.sessionManager.cookie.maxAge |`-1` |Session cookie max age
|shiro.sessionManager.cookie.domain |null |Session cookie domain
|shiro.sessionManager.cookie.path |null |Session cookie path
|shiro.sessionManager.cookie.secure |`false` |Session cookie secure flag
|shiro.rememberMeManager.cookie.name |`rememberMe` |RememberMe cookie
name
|shiro.rememberMeManager.cookie.maxAge |one year |RememberMe cookie max
age
|shiro.rememberMeManager.cookie.domain |null |RememberMe cookie domain
|shiro.rememberMeManager.cookie.path |null |RememberMe cookie path
|shiro.rememberMeManager.cookie.secure |`false` |RememberMe cookie
secure flag
|shiro.loginUrl |`/login.jsp` |Login URL used when unauthenticated users
are redirected to login page
|shiro.successUrl |`/` |Default landing page after a user logs in (if
alternative cannot be found in the current session)
|shiro.unauthorizedUrl |null |Page to redirect user to if they are
unauthorized (403 page)
|===