Document Migration to SecurityContextHolderFilter
Closes gh-12098
This commit is contained in:
		
							parent
							
								
									1dd13e69a4
								
							
						
					
					
						commit
						aac1261f0c
					
				| 
						 | 
				
			
			@ -13,6 +13,21 @@ endif::[]
 | 
			
		|||
 | 
			
		||||
== Servlet
 | 
			
		||||
 | 
			
		||||
=== Explicit Save SecurityContextRepository
 | 
			
		||||
 | 
			
		||||
In Spring Security 5, the default behavior is for the xref:servlet/authentication/architecture.adoc#servlet-authentication-securitycontext[`SecurityContext`] to automatically be saved to the xref:servlet/authentication/persistence.adoc#securitycontextrepository[`SecurityContextRepository`] using the xref:servlet/authentication/persistence.adoc#securitycontextpersistencefilter[`SecurityContextPersistenceFilter`].
 | 
			
		||||
Saving must be done just prior to the `HttpServletResponse` being committed and just before `SecurityContextPersistenceFilter`.
 | 
			
		||||
Unfortunately, automatic persistence of the `SecurityContext` can surprise users when it is done prior to the request completing (i.e. just prior to committing the `HttpServletResponse`).
 | 
			
		||||
It also is complex to keep track of the state to determine if a save is necessary causing unnecessary writes to the `SecurityContextRepository` (i.e. `HttpSession`) at times.
 | 
			
		||||
 | 
			
		||||
In Spring Security 6, the default behavior is that the xref:servlet/authentication/persistence.adoc#securitycontextholderfilter[`SecurityContextHolderFilter`] will only read the `SecurityContext` from  `SecurityContextRepository` and populate it in the `SecurityContextHolder`.
 | 
			
		||||
Users now must explicitly save the `SecurityContext` with the `SecurityContextRepository` if they want the `SecurityContext` to persist between requests.
 | 
			
		||||
This removes ambiguity and improves performance by only requiring writing to the `SecurityContextRepository` (i.e. `HttpSession`) when it is necessary.
 | 
			
		||||
 | 
			
		||||
To opt into the new Spring Security 6 default, the following configuration can be used.
 | 
			
		||||
 | 
			
		||||
include::partial$servlet/architecture/security-context-explicit.adoc[]
 | 
			
		||||
 | 
			
		||||
[[requestcache-query-optimization]]
 | 
			
		||||
=== Optimize Querying of `RequestCache`
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -144,29 +144,8 @@ image::{figures}/securitycontextholderfilter.png[]
 | 
			
		|||
<1> Before running the rest of the application, `SecurityContextHolderFilter` loads the `SecurityContext` from the `SecurityContextRepository` and sets it on the `SecurityContextHolder`.
 | 
			
		||||
<2> Next, the application is ran.
 | 
			
		||||
 | 
			
		||||
Unlike, xref:servlet/authentication/persistence.adoc#securitycontextpersistencefilter[`SecurityContextPersisteneFilter`], `SecurityContextHolderFilter` only loads the `SecurityContext` it does not save the `SecurityContext`.
 | 
			
		||||
Unlike, xref:servlet/authentication/persistence.adoc#securitycontextpersistencefilter[`SecurityContextPersistenceFilter`], `SecurityContextHolderFilter` only loads the `SecurityContext` it does not save the `SecurityContext`.
 | 
			
		||||
This means that when using `SecurityContextHolderFilter`, it is required that the `SecurityContext` is explicitly saved.
 | 
			
		||||
 | 
			
		||||
.Explicit Saving of SecurityContext
 | 
			
		||||
====
 | 
			
		||||
.Java
 | 
			
		||||
[source,java,role="primary"]
 | 
			
		||||
----
 | 
			
		||||
public SecurityFilterChain filterChain(HttpSecurity http) {
 | 
			
		||||
	http
 | 
			
		||||
		// ...
 | 
			
		||||
		.securityContext((securityContext) -> securityContext
 | 
			
		||||
			.requireExplicitSave(true)
 | 
			
		||||
		);
 | 
			
		||||
	return http.build();
 | 
			
		||||
}
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
.XML
 | 
			
		||||
[source,xml,role="secondary"]
 | 
			
		||||
----
 | 
			
		||||
<http security-context-explicit-save="true">
 | 
			
		||||
	<!-- ... -->
 | 
			
		||||
</http>
 | 
			
		||||
----
 | 
			
		||||
====
 | 
			
		||||
include::partial$servlet/architecture/security-context-explicit.adoc[]
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,76 @@
 | 
			
		|||
.Explicit Saving of SecurityContext
 | 
			
		||||
====
 | 
			
		||||
.Java
 | 
			
		||||
[source,java,role="primary"]
 | 
			
		||||
----
 | 
			
		||||
public SecurityFilterChain filterChain(HttpSecurity http) {
 | 
			
		||||
	http
 | 
			
		||||
		// ...
 | 
			
		||||
		.securityContext((securityContext) -> securityContext
 | 
			
		||||
			.requireExplicitSave(true)
 | 
			
		||||
		);
 | 
			
		||||
	return http.build();
 | 
			
		||||
}
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
.Kotlin
 | 
			
		||||
[source,kotlin,role="secondary"]
 | 
			
		||||
----
 | 
			
		||||
@Bean
 | 
			
		||||
open fun springSecurity(http: HttpSecurity): SecurityFilterChain {
 | 
			
		||||
    http {
 | 
			
		||||
        securityContext {
 | 
			
		||||
            requireExplicitSave = true
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return http.build()
 | 
			
		||||
}
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
.XML
 | 
			
		||||
[source,xml,role="secondary"]
 | 
			
		||||
----
 | 
			
		||||
<http security-context-explicit-save="true">
 | 
			
		||||
	<!-- ... -->
 | 
			
		||||
</http>
 | 
			
		||||
----
 | 
			
		||||
====
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
Upon using the configuration, it is important that any code that sets the `SecurityContextHolder` with a `SecurityContext` also saves the `SecurityContext` to the `SecurityContextRepository` if it should be persisted between requests.
 | 
			
		||||
 | 
			
		||||
For example, the following code:
 | 
			
		||||
 | 
			
		||||
.Setting `SecurityContextHolder` with `SecurityContextPersistenceFilter`
 | 
			
		||||
====
 | 
			
		||||
.Java
 | 
			
		||||
[source,java,role="primary"]
 | 
			
		||||
----
 | 
			
		||||
SecurityContextHolder.setContext(securityContext);
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
.Kotlin
 | 
			
		||||
[source,kotlin,role="secondary"]
 | 
			
		||||
----
 | 
			
		||||
SecurityContextHolder.setContext(securityContext)
 | 
			
		||||
----
 | 
			
		||||
====
 | 
			
		||||
 | 
			
		||||
should be replaced with
 | 
			
		||||
 | 
			
		||||
.Setting `SecurityContextHolder` with `SecurityContextHolderFilter`
 | 
			
		||||
====
 | 
			
		||||
.Java
 | 
			
		||||
[source,java,role="primary"]
 | 
			
		||||
----
 | 
			
		||||
SecurityContextHolder.setContext(securityContext);
 | 
			
		||||
securityContextRepository.saveContext(securityContext, httpServletRequest, httpServletResponse);
 | 
			
		||||
----
 | 
			
		||||
 | 
			
		||||
.Kotlin
 | 
			
		||||
[source,kotlin,role="secondary"]
 | 
			
		||||
----
 | 
			
		||||
SecurityContextHolder.setContext(securityContext)
 | 
			
		||||
securityContextRepository.saveContext(securityContext, httpServletRequest, httpServletResponse)
 | 
			
		||||
----
 | 
			
		||||
====
 | 
			
		||||
		Loading…
	
		Reference in New Issue