Session Management Migrations
The following steps relate to how to finish migrating session management support.
Require Explicit Saving of SecurityContextRepository
In Spring Security 5, the default behavior is for the SecurityContext
to automatically be saved to the SecurityContextRepository
using the 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 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.
Saving the context is also needed when clearing it out, for example during logout. Refer to this section to know more about that. |
If you are explicitly opting into Spring Security 6’s new defaults, the following configuration can be removed to accept the Spring Security 6 defaults.
-
Java
-
Kotlin
-
XML
public SecurityFilterChain filterChain(HttpSecurity http) {
http
// ...
.securityContext((securityContext) -> securityContext
.requireExplicitSave(true)
);
return http.build();
}
@Bean
open fun springSecurity(http: HttpSecurity): SecurityFilterChain {
http {
securityContext {
requireExplicitSave = true
}
}
return http.build()
}
<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:
SecurityContextHolder
with SecurityContextPersistenceFilter
-
Java
-
Kotlin
SecurityContextHolder.setContext(securityContext);
SecurityContextHolder.setContext(securityContext)
should be replaced with
SecurityContextHolder
with SecurityContextHolderFilter
-
Java
-
Kotlin
SecurityContextHolder.setContext(securityContext);
securityContextRepository.saveContext(securityContext, httpServletRequest, httpServletResponse);
SecurityContextHolder.setContext(securityContext)
securityContextRepository.saveContext(securityContext, httpServletRequest, httpServletResponse)
Multiple SecurityContextRepository
In Spring Security 5, the default SecurityContextRepository
was HttpSessionSecurityContextRepository
.
In Spring Security 6, the default SecurityContextRepository
is DelegatingSecurityContextRepository
.
If you configured the SecurityContextRepository
only for the purpose of updating to 6.0, you can remove it completely.
Optimize Querying of RequestCache
In Spring Security 5, the default behavior is to query the saved request on every request.
This means that in a typical setup, that in order to use the RequestCache
the HttpSession
is queried on every request.
In Spring Security 6, the default is that RequestCache
will only be queried for a cached request if the HTTP parameter continue
is defined.
This allows Spring Security to avoid unnecessarily reading the HttpSession
with the RequestCache
.
In Spring Security 5 the default is to use HttpSessionRequestCache
which will be queried for a cached request on every request.
If you are not overriding the defaults (i.e. using NullRequestCache
), then the following configuration can be used to explicitly opt into the Spring Security 6 behavior in Spring Security 5.8:
RequestCache
Only Checks for Saved Requests if continue
Parameter Present-
Java
-
Kotlin
-
XML
@Bean
DefaultSecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
HttpSessionRequestCache requestCache = new HttpSessionRequestCache();
requestCache.setMatchingRequestParameterName("continue");
http
// ...
.requestCache((cache) -> cache
.requestCache(requestCache)
);
return http.build();
}
@Bean
open fun springSecurity(http: HttpSecurity): SecurityFilterChain {
val httpRequestCache = HttpSessionRequestCache()
httpRequestCache.setMatchingRequestParameterName("continue")
http {
requestCache {
requestCache = httpRequestCache
}
}
return http.build()
}
<http auto-config="true">
<!-- ... -->
<request-cache ref="requestCache"/>
</http>
<b:bean id="requestCache" class="org.springframework.security.web.savedrequest.HttpSessionRequestCache"
p:matchingRequestParameterName="continue"/>