You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shiro.apache.org by bm...@apache.org on 2021/09/10 20:56:38 UTC

[shiro-site] 01/06: [JBake][Content] convert spring pages.

This is an automated email from the ASF dual-hosted git repository.

bmarwell pushed a commit to branch jbake
in repository https://gitbox.apache.org/repos/asf/shiro-site.git

commit 3e8f5ea057edd7d633c28cb111d231450cddf055
Author: Benjamin Marwell <bm...@apache.org>
AuthorDate: Wed Sep 8 23:07:33 2021 +0200

    [JBake][Content] convert spring pages.
---
 jbake/.gitignore                             |   3 +
 jbake/content/spring-boot.adoc               | 200 ++++++++++++++++++++
 jbake/content/spring-framework.adoc          | 270 +++++++++++++++++++++++++++
 spring-xml.md => jbake/content/spring-xml.md |  46 ++---
 jbake/jbake.properties                       |   3 +
 jbake/templates/header.ftl                   |   1 +
 jbake/templates/macros/dependencies.ftl      | 101 ++++++++++
 spring-boot.md.vtl                           | 171 -----------------
 spring-framework.md.vtl                      | 215 ---------------------
 templates/macros/dependencies.vtl            |  24 ---
 10 files changed, 598 insertions(+), 436 deletions(-)

diff --git a/jbake/.gitignore b/jbake/.gitignore
index 9adf614..6ef6ecf 100644
--- a/jbake/.gitignore
+++ b/jbake/.gitignore
@@ -1,2 +1,5 @@
 output
 /target/
+.project
+.settings
+cache
\ No newline at end of file
diff --git a/jbake/content/spring-boot.adoc b/jbake/content/spring-boot.adoc
new file mode 100644
index 0000000..590fdb8
--- /dev/null
+++ b/jbake/content/spring-boot.adoc
@@ -0,0 +1,200 @@
+= Integrating Apache Shiro into Spring-Boot Applications
+:jbake-type: page
+:jbake-status: published
+:jbake-tags: documentation, manual, spring
+:idprefix:
+:toc:
+
+Shiro's Spring-Boot integration is the easiest way to integrate Shiro into a Spring-base application, for more general Spring Framework integration, take a the link:spring-framework.html[annotation] or link:spring-xml.html[XML] guides.
+
+== 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.
+
+First include the Shiro Spring web starter dependency in you application classpath (we recomend using a tool such as Apache Maven or Gradle to manage this).
+
+++++
+<@dependencies anchorId="web" deps=[{"g":"org.apache.shiro", "a":"shiro-spring-boot-web-starter", "v":"${latestRelease}"}] />
+++++
+
+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-boot-web[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 automatically in both starters listed 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:caching.html[CacheManager] bean:
+
+[source,java]
+----
+@Bean
+protected CacheManager cacheManager() {
+    return new MemoryConstrainedCacheManager();
+}
+----
+
+=== Configuration Properties
+
+[width="100%",cols="36%,24%,40%",options="header",]
+|===
+|Key |Default Value |Description
+
+|shiro.enabled
+|`true`
+|Enables Shiro’s Spring module
+
+|shiro.web.enabled
+|`true`
+|Enables Shiro’s Spring web module
+
+|shiro.annotations.enabled |`true` |Enables Spring support for Shiro’s annotations
+
+|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)
+|===
+
+== Standalone Applications
+
+Include the Shiro Spring starter dependency in you application classpath (we recomend using a tool such as Apache Maven or Gradle to manage this).
+
+++++
+<@dependencies anchorId="cli" deps=[{"g":"org.apache.shiro", "a":"shiro-spring-boot-starter", "v":"${latestRelease}"}] />
+++++
+
+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:#Spring-WebApplications[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-boot[samples on Github].
diff --git a/jbake/content/spring-framework.adoc b/jbake/content/spring-framework.adoc
new file mode 100644
index 0000000..ea3001a
--- /dev/null
+++ b/jbake/content/spring-framework.adoc
@@ -0,0 +1,270 @@
+= Integrating Apache Shiro into Spring-based Applications
+:jbake-type: page
+:jbake-status: published
+:jbake-tags: documentation, manual, spring
+:idprefix:
+:toc:
+
+This page covers the ways to integrate Shiro into link:http://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 anchorId="cli" deps=[{'g':'org.apache.shiro', 'a':'shiro-spring', "v":"${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 Shiro’s lifecycle and events
+
+|org.apache.shiro.spring.config.ShiroConfiguration
+|Configures Shiro Beans (SecurityManager, SessionManager, etc)
+
+|org.apache.shiro.spring.config.ShiroAnnotationProcessorConfiguration
+|Enables Shiro’s 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
+
+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 anchorId="web" deps=[{"g":'org.apache.shiro', "a":'shiro-spring', "v":"${latestRelease}"}, {"g":'org.apache.shiro', "a":'shiro-web', "v":"${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 Shiro’s lifecycle and events
+
+|org.apache.shiro.spring.config.ShiroAnnotationProcessorConfiguration
+|Enables Shiro’s 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 Shiro’s web filter
+
+|org.apache.shiro.spring.web.config.ShiroRequestMappingConfig
+|Configures Spring with Shiro’s `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:http://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)
+|===
+
+
+
diff --git a/spring-xml.md b/jbake/content/spring-xml.md
similarity index 92%
rename from spring-xml.md
rename to jbake/content/spring-xml.md
index a4c5eb3..81321c1 100644
--- a/spring-xml.md
+++ b/jbake/content/spring-xml.md
@@ -1,16 +1,19 @@
-<a name="SpringXml-IntegratingApacheShirointoSpringbasedApplications"></a>
-#Integrating Apache Shiro into Spring-based Applications
+title=Integrating Apache Shiro into Spring-based Applications
+type=page
+tags=documentation, manual
+status=published
+~~~~~~
 
 This page covers the ways to integrate Shiro into [Spring](http://spring.io)-based applications.
 
 Shiro's JavaBeans compatibility makes it perfectly suited to be configured via Spring XML or other Spring-based configuration mechanisms. Shiro applications need an application singleton `SecurityManager` instance. Note that this does not have to be a _static_ singleton, but there should only be a single instance used by the application, whether its a static singleton or not.
 
-## <a name="SpringXml-StandaloneApplications"></a>Standalone Applications
+## Standalone Applications
 
 Here is the simplest way to enable an application singleton `SecurityManager` in Spring applications:
 
 
-``` xml
+```xml
 <!-- Define the realm you want to use to connect to your back-end security datasource: -->
 <bean id="myRealm" class="...">
     ...
@@ -32,7 +35,6 @@ Here is the simplest way to enable an application singleton `SecurityManager` in
 </bean>
 ```
 
-<a name="SpringXml-WebApplications"></a>
 ## Web Applications
 
 Shiro has first-rate 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
@@ -45,12 +47,11 @@ Now in Shiro 1.0 and later, all Shiro configuration is done in Spring XML provid
 
 Here is how to configure Shiro in a Spring-based web application:
 
-<a name="SpringXml-web.xml"></a>
 ### web.xml
 
 In addition to your other Spring web.xml elements (`ContextLoaderListener`, `Log4jConfigListener`, etc), define the following filter and filter mapping:
 
-``` xml
+```xml
 <!-- The filter-name matches name of a 'shiroFilter' bean inside applicationContext.xml -->
 <filter>
     <filter-name>shiroFilter</filter-name>
@@ -74,12 +75,11 @@ In addition to your other Spring web.xml elements (`ContextLoaderListener`, `Log
 
 You can see a full example in our [samples on Github](https://github.com/apache/shiro/tree/main/samples/spring-xml).
 
-<a name="SpringXml-applicationContext.xml"></a>
-###applicationContext.xml
+### applicationContext.xml
 
 In your applicationContext.xml file, define the web-enabled `SecurityManager` and the 'shiroFilter' bean that will be referenced from `web.xml`.
 
-``` xml
+```xml
 <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
     <property name="securityManager" ref="securityManager"/>
     <!-- override these for application-specific URLs if you like:
@@ -129,14 +129,13 @@ In your applicationContext.xml file, define the web-enabled `SecurityManager` an
 </bean>
 ```
 
-<a name="SpringXml-EnablingShiroAnnotations"></a>
-##Enabling Shiro Annotations
+## 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. This requires Shiro's Spring AOP integration to scan for the appropriate annotated classes and perform security logic as necessary.
 
 Here is how to enable these annotations. Just add these two bean definitions to `applicationContext.xml`:
 
-``` xml
+```xml
 <!-- Enable Shiro Annotations for Spring-configured beans.  Only run after -->
 <!-- the lifecycleBeanProcessor has run: -->
 <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor"/>
@@ -145,17 +144,15 @@ Here is how to enable these annotations. Just add these two bean definitions to
 </bean>
 ```
 
-<a name="SpringXml-SecureSpringRemoting"></a>
-##Secure Spring Remoting
+## Secure Spring Remoting
 
 There are two parts to Shiro's Spring remoting support: Configuration for the client making the remoting call and configuration for the server receiving and processing the remoting call.
 
-<a name="SpringXml-ServersideConfiguration"></a>
-###Server-side Configuration
+### Server-side Configuration
 
 When a remote method invocation comes in to a Shiro-enabled server, the [Subject](subject.html "Subject") associated with that RPC call must be bound to the receiving thread for access during the thread's execution. This is done by defining Shiro's `SecureRemoteInvocationExecutor` bean in `applicationContext.xml`:
 
-``` xml
+```xml
 <!-- Secure Spring remoting:  Ensure any Spring Remoting method invocations -->
 <!-- can be associated with a Subject for security checks. -->
 <bean id="secureRemoteInvocationExecutor" class="org.apache.shiro.spring.remoting.SecureRemoteInvocationExecutor">
@@ -167,7 +164,7 @@ Once you have defined this bean, you must plug it in to whatever remoting `Expor
 
 For example, if using HTTP-based remoting (notice the property reference to the `secureRemoteInvocationExecutor` bean):
 
-``` xml
+```xml
 <bean name="/someService" class="org.springframework.remoting.httpinvoker.HttpInvokerServiceExporter">
     <property name="service" ref="someService"/>
     <property name="serviceInterface" value="com.pkg.service.SomeService"/>
@@ -175,12 +172,11 @@ For example, if using HTTP-based remoting (notice the property reference to the
 </bean>
 ```
 
-<a name="SpringXml-ClientsideConfiguration"></a>
-###Client-side Configuration
+### Client-side Configuration
 
 When a remote call is being executed, the `Subject` identifying information must be attached to the remoting payload to let the server know who is making the call. If the client is a Spring-based client, that association is done via Shiro's `SecureRemoteInvocationFactory`:
 
-``` xml
+```xml
 <bean id="secureRemoteInvocationFactory" class="org.apache.shiro.spring.remoting.SecureRemoteInvocationFactory"/>
 ```
 
@@ -188,7 +184,7 @@ Then after you've defined this bean, you need to plug it in to the protocol-spec
 
 For example, if you were using HTTP-based remoting (notice the property reference to the `secureRemoteInvocationFactory` bean defined above):
 
-``` xml
+```xml
 <bean id="someService" class="org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean">
     <property name="serviceUrl" value="http://host:port/remoting/someService"/>
     <property name="serviceInterface" value="com.pkg.service.SomeService"/>
@@ -196,10 +192,8 @@ For example, if you were using HTTP-based remoting (notice the property referenc
 </bean>
 ```
 
-<a name="SpringXml-Lendahandwithdocumentation"></a>
-##Lend a hand with documentation
+## 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 send it to the [User Forum](http://shiro-user.582556.n2.nabble.com/) or the [User Mailing List](mailing-lists.html "Mailing Lists").
-<input type="hidden" id="ghEditPage" value="spring-xml.md"></input>
diff --git a/jbake/jbake.properties b/jbake/jbake.properties
index 3ab2072..60e0431 100644
--- a/jbake/jbake.properties
+++ b/jbake/jbake.properties
@@ -8,3 +8,6 @@ render.archive=true
 
 template.download.file=download.ftl
 template.lend_a_hand.file=lend_a_hand.ftl
+
+db.store=plocal
+db.path=cache
\ No newline at end of file
diff --git a/jbake/templates/header.ftl b/jbake/templates/header.ftl
index 81fde94..e60c075 100644
--- a/jbake/templates/header.ftl
+++ b/jbake/templates/header.ftl
@@ -16,6 +16,7 @@
    limitations under the License.
 -->
 <#include "macros/versions.ftl">
+<#include "macros/dependencies.ftl">
 <html lang="en">
   <head>
     <meta charset="utf-8"/>
diff --git a/jbake/templates/macros/dependencies.ftl b/jbake/templates/macros/dependencies.ftl
new file mode 100644
index 0000000..ab2850a
--- /dev/null
+++ b/jbake/templates/macros/dependencies.ftl
@@ -0,0 +1,101 @@
+<#macro dependencies anchorId deps=[] >
+<ul class="nav nav-tabs" id="dependency-${anchorId}-tab" role="tablist">
+  <#-- maven -->
+  <li class="nav-item" role="presentation">
+    <button
+      class="nav-link active"
+      id="maven-${anchorId}-tab"
+      data-bs-toggle="tab"
+      data-bs-target="#maven-${anchorId}"
+      type="button"
+      role="tab"
+      aria-controls="maven-${anchorId}"
+      aria-selected="true"
+      >Maven</button>
+  </li>
+  <#-- gradle -->
+  <li class="nav-item" role="presentation">
+    <button
+      class="nav-link"
+      id="gradle-${anchorId}-tab"
+      data-bs-toggle="tab"
+      data-bs-target="#gradle-${anchorId}"
+      type="button"
+      role="tab"
+      aria-controls="gradle-${anchorId}"
+      aria-selected="false"
+      >Gradle</button>
+  </li>
+  <#-- ivy -->
+  <li class="nav-item" role="presentation">
+    <button
+      class="nav-link"
+      id="ivy-${anchorId}-tab"
+      data-bs-toggle="tab"
+      data-bs-target="#ivy-${anchorId}"
+      type="button"
+      role="tab"
+      aria-controls="ivy-${anchorId}"
+      aria-selected="false"
+      >Ivy</button>
+  </li>
+  <#-- Leiningen -->
+  <li class="nav-item" role="presentation">
+    <button
+      class="nav-link"
+      id="leiningen-${anchorId}-tab"
+      data-bs-toggle="tab"
+      data-bs-target="#leiningen-${anchorId}"
+      type="button"
+      role="tab"
+      aria-controls="leiningen-${anchorId}"
+      aria-selected="false"
+    >Leiningen</button>
+  </li>
+</ul>
+<div class="tab-content" id="dependency-${anchorId}-tab-content">
+  <div
+    class="tab-pane fade show active"
+    id="maven-${anchorId}"
+    role="tabpanel"
+    aria-labelledby="maven-${anchorId}-tab"
+    >
+    <pre><code class='xml language-xml'><#list deps as dep>&lt;dependency&gt;
+  &lt;groupId&gt;${dep.g}&lt;/groupId&gt;
+  &lt;artifactId&gt;${dep.a}&lt;/artifactId&gt;
+  &lt;version&gt;${dep.v}&lt;/version&gt;
+&lt;/dependency&gt;
+</#list></code></pre>
+  </div>
+  <#-- gradle -->
+  <div
+    class="tab-pane fade"
+    id="gradle-${anchorId}"
+    role="tabpanel"
+    aria-labelledby="gradle-${anchorId}-tab"
+    >
+    <pre><code class='groovy language-groovy'><#list deps as dep>compile '${dep.g}:${dep.a}:${dep.v}'
+</#list></code></pre>
+  </div>
+  <#-- ivy -->
+  <div
+    class="tab-pane fade"
+    id="ivy-${anchorId}"
+    role="tabpanel"
+    aria-labelledby="ivy-${anchorId}-tab"
+    >
+    <pre><code class='xml language-xml'><#list deps as dep>&lt;dependency org="${dep.g}" name="${dep.a}" rev="${dep.v}"/&gt;
+</#list></code></pre>
+  </div>
+  <#-- Leiningen -->
+  <div
+    class="tab-pane fade"
+    id="leiningen-${anchorId}"
+    role="tabpanel"
+    aria-labelledby="leiningen-${anchorId}-tab"
+    >
+    <pre><code class='clojure language-clojure'><#list deps as dep>[${dep.g}/${dep.a} "${dep.v}"]
+</#list></code></pre>
+  </div>
+</div>
+</#macro>
diff --git a/spring-boot.md.vtl b/spring-boot.md.vtl
deleted file mode 100644
index 64a124d..0000000
--- a/spring-boot.md.vtl
+++ /dev/null
@@ -1,171 +0,0 @@
-#parse("templates/includes.vtl")
-
-<a name="Spring-IntegratingApacheShirointoSpringbasedApplications"></a>
-#Integrating Apache Shiro into Spring-Boot Applications
-
-Shiro's Spring-Boot integration is the easiest way to integrate Shiro into a Spring-base application, for more general Spring Framework integration, take a the [annotation](spring-framework.html) or [XML](spring-xml.html) guides.  
-
-<a name="Spring-WebApplications"></a>
-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.
-
-First include the Shiro Spring web starter dependency in you application classpath (we recomend using a tool such as Apache Maven or Gradle to manage this).
-
-#dependencies('web', [['org.apache.shiro', 'shiro-spring-boot-web-starter', "${latestRelease}"]])
-
-Provide a Realm implementation:
-``` 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. 
-
-``` 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 [annotation](#Spring-annotations-web) section below.
-
-You can see a full example in our [samples on Github](https://github.com/apache/shiro/tree/main/samples/spring-boot-web).
-
-<a name="Spring-annotations"></a>
-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 automatically in both starters listed above.
-
-Simply annotate your methods in order to use them:
-
-``` java
-@RequiresPermissions("document:read")
-public void readDocument() {
-    ...
-}
-```
-
-<a name="Spring-annotations-web"></a>
-#[[###]]# Annotations and Web Applications
-
-Shiro annotations are fully supported for use in `@Controller` classes, for example:
-
-``` 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]`.
-
-``` 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;
-}
-```
-
-<a name="Spring-caching"></a>
-# Caching 
-
-Enabling caching is as simple as providing a [CacheManager](http://shiro.apache.org/caching.html) bean:
-
-``` java
-@Bean
-protected CacheManager cacheManager() {
-    return new MemoryConstrainedCacheManager();
-}
-```
-
-<!-- Work around for table styling until, all pages are updated. -->
-#mdStyle()
-
-# Configuration Properties
-
-| Key | Default Value | Description |
-| --- | ------------- | ----------- |
-| shiro.enabled | `true` | Enables Shiro's Spring module |
-| shiro.web.enabled | `true` | Enables Shiro's Spring web module |
-| shiro.annotations.enabled | `true` | Enables Spring support for Shiro's annotations |
-| 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) |
-
-<a name="Spring-StandaloneApplications"></a>
-# Standalone Applications
-
-Include the Shiro Spring starter dependency in you application classpath (we recomend using a tool such as Apache Maven or Gradle to manage this).
-
-#dependencies('cli', [['org.apache.shiro', 'shiro-spring-boot-starter', "${latestRelease}"]])
-
-The only thing that is left is to configure a [realm](realm.html):
-
-``` 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 [Web Applications](#Spring-WebApplications) section below instead.
- 
-``` java
-@Autowired
-private SecurityManager securityManager;
-    
- @PostConstruct
- private void initStaticSecurityManager() {
-     SecurityUtils.setSecurityManager(securityManager);
- }
-```
-
-That is it, now you can get the current `Subject` using:
-
-``` java
-SecurityUtils.getSubject();
-```
-
-You can see a full example in our [samples on Github](https://github.com/apache/shiro/tree/main/samples/spring-boot).
-
-<input type="hidden" id="ghEditPage" value="spring-boot.md.vtl"></input>
diff --git a/spring-framework.md.vtl b/spring-framework.md.vtl
deleted file mode 100644
index 23ea725..0000000
--- a/spring-framework.md.vtl
+++ /dev/null
@@ -1,215 +0,0 @@
-#parse("templates/includes.vtl")
-
-<a name="SpringFramework-IntegratingApacheShirointoSpringbasedApplications"></a>
-Integrating Apache Shiro into Spring-based Applications
-===
-
-This page covers the ways to integrate Shiro into [Spring](http://spring.io)-based applications.
-
-<a name="SpringFramework-StandaloneApplications"></a>
-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('cli', [['org.apache.shiro', 'shiro-spring', "${latestRelease}"],['org.springframework', 'spring-context', '${spring.version}']])
-
-Import the Shiro Spring configurations:
-
-``` java
-@Configuration
-@Import({ShiroBeanConfiguration.class,
-         ShiroConfiguration.class,
-         ShiroAnnotationProcessorConfiguration.class})
-public class CliAppConfig {
-   ...
-}
-```
-
-The above configurations do the following:
-
-| Configuration Class | Description |
-| ------------------- | ----------- |
-| org.apache.shiro.spring.config.ShiroBeanConfiguration | Configures Shiro's lifecycle and events |
-| org.apache.shiro.spring.config.ShiroConfiguration | Configures Shiro Beans (SecurityManager, SessionManager, etc)  |
-| org.apache.shiro.spring.config.ShiroAnnotationProcessorConfiguration | Enables Shiro's annotation processing |
-
-The only thing that is left is to configure a [realm](realm.html):
-
-``` 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 [Web Applications](#Spring-WebApplications) section below instead.
-
-``` java
-@Autowired
-private SecurityManager securityManager;
-    
- @PostConstruct
- private void initStaticSecurityManager() {
-     SecurityUtils.setSecurityManager(securityManager);
- }
-```
-
-That is it, now you can get the current `Subject` using:
-``` java
-SecurityUtils.getSubject();
-```
-
-You can see a full example in our [samples on Github](https://github.com/apache/shiro/tree/main/samples/spring).
-
-<a name="SpringFramework-WebApplications"></a>
-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('web', [['org.apache.shiro', 'shiro-spring', "${latestRelease}"], ['org.apache.shiro', 'shiro-web', "${latestRelease}"],['org.springframework', 'spring-webmvc', '${spring.version}']])
-
-<a name="SpringFramework-WebConfig"></a>
-
-Import the Shiro Spring configurations:
-
-``` java
-@Configuration
-@Import({ShiroBeanConfiguration.class,
-        ShiroAnnotationProcessorConfiguration.class,
-        ShiroWebConfiguration.class,
-        ShiroWebFilterConfiguration.class,
-        ShiroRequestMappingConfig.class})
-public class ApplicationConfig {
-  ...
-}
-```
-
-The above configurations do the following:
-
-| Configuration Class | Description |
-| ------------------- | ----------- |
-| org.apache.shiro.spring.config.ShiroBeanConfiguration | Configures Shiro's lifecycle and events |
-| org.apache.shiro.spring.config.ShiroAnnotationProcessorConfiguration | Enables Shiro's 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 Shiro's web filter |
-| org.apache.shiro.spring.web.config.ShiroRequestMappingConfig | Configures Spring with Shiro's `UrlPathHelper` implementation to ensure URLs are processed the same both frameworks | 
-
-Provide a Realm implementation:
-``` 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. 
-
-``` 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 [annotation](#Spring-annotations-web) section below.
-
-You can see a full example in our [samples on Github](https://github.com/apache/shiro/tree/main/samples/spring-mvc).
-
-<a name="Spring-annotations"></a>
-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:
-
-``` java
-@RequiresPermissions("document:read")
-public void readDocument() {
-    ...
-}
-```
-
-<a name="Spring-annotations-web"></a>
-#[[###]]# Annotations and Web Applications
-
-Shiro annotations are fully supported for use in `@Controller` classes, for example:
-
-``` 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]`.
-
-``` 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;
-}
-```
-
-<a name="Spring-caching"></a>
-# Caching 
-
-Enabling caching is as simple as providing a [CacheManager](http://shiro.apache.org/caching.html) bean:
-
-``` java
-@Bean
-protected CacheManager cacheManager() {
-    return new MemoryConstrainedCacheManager();
-}
-```
-
-<!-- Work around for table styling until, all pages are updated. -->
-#mdStyle()
-
-# Configuration Properties
-
-| 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) |
-
-<input type="hidden" id="ghEditPage" value="spring-framework.md.vtl"></input>
diff --git a/templates/macros/dependencies.vtl b/templates/macros/dependencies.vtl
deleted file mode 100644
index 5e6f71d..0000000
--- a/templates/macros/dependencies.vtl
+++ /dev/null
@@ -1,24 +0,0 @@
-#macro(dependencies, $anchorId, $deps)
-
-<ul class="nav nav-tabs">
-    <li class="active"><a data-toggle="tab" href="#maven-$anchorId">Apache Maven</a></li>
-    <li><a data-toggle="tab" href="#gradle-$anchorId">Gradle</a></li>
-</ul>
-
-<div class="tab-content">
-    <div id="maven-$anchorId" class="tab-pane fade in active">
-    <pre><code class='xml'>#foreach($item in $deps)&lt;dependency&gt;
-    &lt;groupId&gt;$item[0]&lt;/groupId&gt;
-    &lt;artifactId&gt;$item[1]&lt;/artifactId&gt;
-    &lt;version&gt;$item[2]&lt;/version&gt;
-&lt;/dependency&gt;
-#end
-</code></pre>
-    </div>
-    <div id="gradle-$anchorId" class="tab-pane fade">
-        <pre><code class='groovy'>#foreach($item in $deps)
-compile '$item[0]:$item[1]:$item[2]'
-#end</code></pre>
-    </div>
-</div>
-#end
\ No newline at end of file