diff --git a/docs/modules/ROOT/pages/migration.adoc b/docs/modules/ROOT/pages/migration.adoc index ec10cc6c39..96dc02b0b2 100644 --- a/docs/modules/ROOT/pages/migration.adoc +++ b/docs/modules/ROOT/pages/migration.adoc @@ -193,6 +193,91 @@ To opt into the new Spring Security 6 default, the following configuration can b include::partial$servlet/architecture/security-context-explicit.adoc[] +=== Deprecation in SecurityContextRepository + +In Spring Security 5.7, a new method was added to xref:servlet/authentication/persistence.adoc#securitycontextrepository[`SecurityContextRepository`] with the signature: + + Supplier loadContext(HttpServletRequest request) + +With the addition of xref:servlet/authentication/persistence.adoc#delegatingsecuritycontextrepository[`DelegatingSecurityContextRepository`] in Spring Security 5.8, that method was deprecated in favor of a new method with the signature: + + DeferredSecurityContext loadDeferredContext(HttpServletRequest request) + +In Spring Security 6, the deprecated method was removed. +If you have implemented `SecurityContextRepository` yourself and added an implementation of the `loadContext(request)` method, you can prepare for Spring Security 6 by removing the implementation of that method and implementing the new method instead. + +To get started implementing the new method, use the following example that adapts a `Supplier` to provide a `DeferredSecurityContext`: + +[NOTE] +==== +The adapted `Supplier` should return `null` when no `SecurityContext` is available, which was not the case with the `Supplier` returned from `loadContext(request)`. +==== + +.Adapt `Supplier` to `DeferredSecurityContext` +==== +.Java +[source,java,role="primary"] +---- +@Override +public DeferredSecurityContext loadDeferredContext(HttpServletRequest request) { + // Adapt a supplier that returns null when the context is not available + Supplier supplier = () -> getContextOrNull(request); + SecurityContextHolderStrategy strategy = SecurityContextHolder.getContextHolderStrategy(); + return new DeferredSecurityContext() { + private SecurityContext securityContext; + private boolean isGenerated; + + @Override + public SecurityContext get() { + if (this.securityContext == null) { + this.securityContext = supplier.get(); + if (this.securityContext == null) { + this.securityContext = strategy.createEmptyContext(); + this.isGenerated = true; + } + } + return this.securityContext; + } + + @Override + public boolean isGenerated() { + get(); + return this.isGenerated; + } + }; +} +---- + +.Kotlin +[source,kotlin,role="secondary"] +---- +override fun loadDeferredContext(request: HttpServletRequest): DeferredSecurityContext { + // Adapt a supplier that returns null when the context is not available + val supplier: Supplier = SingletonSupplier.of { + getContextOrNull(request) + } + val strategy = SecurityContextHolder.getContextHolderStrategy() + return object : DeferredSecurityContext { + private var securityContext: SecurityContext? = null + private var isGenerated = false + + override fun get(): SecurityContext { + if (securityContext == null) { + securityContext = supplier.get() + ?: strategy.createEmptyContext().also { isGenerated = true } + } + return securityContext!! + } + + override fun isGenerated(): Boolean { + get() + return isGenerated + } + } +} +---- +==== + [[requestcache-query-optimization]] === Optimize Querying of `RequestCache`