mirror of
https://github.com/spring-projects/spring-security.git
synced 2025-06-12 07:02:13 +00:00
Merge branch '6.5.x'
This commit is contained in:
commit
9c357984d7
7
docs/modules/ROOT/pages/migration-7/acl.adoc
Normal file
7
docs/modules/ROOT/pages/migration-7/acl.adoc
Normal file
@ -0,0 +1,7 @@
|
||||
= ACL
|
||||
|
||||
== Favor `AclPermissionEvaluator`
|
||||
|
||||
`AclEntryVoter`, `AclEntryAfterInvocationProvider`, and `AclPermissionEvaluator` provide the same service, plugged into different Spring Security APIs. Now that `AccessDecisionVoter` and `AfterInvocationProvider` are both deprecated, the corresponding ACL plugins are obsolete.
|
||||
|
||||
As such, begin using `AclPermissionEvaluator` before updating to Spring Security 7.
|
@ -1,68 +1,2 @@
|
||||
= Authentication Changes
|
||||
|
||||
== Opaque Token Credentials Will Be Encoded For You
|
||||
|
||||
In order to comply more closely with the Introspection RFC, Spring Security's opaque token support will encode the client id and secret before creating the authorization header.
|
||||
This change means you will no longer have to encode the client id and secret yourself.
|
||||
|
||||
If your client id or secret contain URL-unsafe characters, then you can prepare yourself for this change by doing the following:
|
||||
|
||||
=== Replace Usage of `introspectionClientCredentials`
|
||||
|
||||
Since Spring Security can now do the encoding for you, replace xref:servlet/oauth2/resource-server/opaque-token.adoc#oauth2resourceserver-opaque-introspectionuri-dsl[using `introspectionClientCredentials`] with publishing the following `@Bean`:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
OpaqueTokenIntrospector introspector() {
|
||||
return SpringOpaqueTokenIntrospector.withIntrospectionUri(introspectionUri)
|
||||
.clientId(unencodedClientId).clientSecret(unencodedClientSecret).build();
|
||||
}
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@Bean
|
||||
fun introspector(): OpaqueTokenIntrospector {
|
||||
return SpringOpaqueTokenIntrospector.withIntrospectionUri(introspectionUri)
|
||||
.clientId(unencodedClientId).clientSecret(unencodedClientSecret).build()
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
The above will be the default in 7.0.
|
||||
|
||||
If this setting gives you trouble or you cannot apply it for now, you can use the `RestOperations` constructor instead:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
OpaqueTokenIntrospector introspector() {
|
||||
RestTemplate rest = new RestTemplate();
|
||||
rest.addInterceptor(new BasicAuthenticationInterceptor(encodedClientId, encodedClientSecret));
|
||||
return new SpringOpaqueTokenIntrospector(introspectionUri, rest);
|
||||
}
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@Bean
|
||||
fun introspector(): OpaqueTokenIntrospector {
|
||||
val rest = RestTemplate()
|
||||
rest.addInterceptor(BasicAuthenticationInterceptor(encodedClientId, encodedClientSecret))
|
||||
return SpringOpaqueTokenIntrospector(introspectionUri, rest)
|
||||
}
|
||||
----
|
||||
======
|
||||
|
@ -22,3 +22,82 @@ public void doSomething(Long id) {
|
||||
|
||||
You must compile with `-parameters` to ensure that the parameter names are available at runtime.
|
||||
For more information about this, please visit the https://github.com/spring-projects/spring-framework/wiki/Upgrading-to-Spring-Framework-6.x#core-container[Upgrading to Spring Framework 6.1 page].
|
||||
|
||||
=== Favor `AnnotationTemplateExpressionDefaults` over `PrePostTemplateDefaults`
|
||||
|
||||
In Spring Security 7, `AnnotationTemplateExpressionDefaults` will be included by default.
|
||||
|
||||
If you are customizing `PrePostTemplateDefaults` or simply want to see how your application responds to `AnnotationTemplateExpressionDefaults`, you can publish an `AnnotationTemplateExpressionDefaults` bean instead of a `PrePostTemplateDefaults` method:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
static AnnotationTemplateExpressionDefaults templateExpressionDefaults() {
|
||||
return new AnnotationTemplateExpressionDefaults();
|
||||
}
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
companion object {
|
||||
@Bean
|
||||
fun templateExpressionDefaults() = AnnotationTemplateExpressionDefaults()
|
||||
}
|
||||
----
|
||||
|
||||
Xml::
|
||||
+
|
||||
[source,xml,role="secondary"]
|
||||
----
|
||||
<b:bean id="templateExpressionDefaults" class="org.springframework.security.core.annotation.AnnotationTemplateExpressionDefaults"/>
|
||||
----
|
||||
======
|
||||
|
||||
==== I Am Publishing an AuthorizationAdvisor Bean
|
||||
|
||||
If you are publishing an `AuthorizationAdvisor` bean, like `AuthorizationManagerBeforeMethodInterceptor`, `AuthorizationManagerAfterMethodInterceptor`, `PreFilterAuthorizationMethodInterceptor`, or `PostFilterAuthorizationMethodInterceptor`, you can do the same by calling `setTemplateDefaults` with an `AnnotationTemplateExpressionDefaults` instance instead:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
@Role(BeanDescription.ROLE_INFRASTRUCTURE)
|
||||
static Advisor preFilter() {
|
||||
PreFilterAuthorizationMethodInterceptor interceptor = new PreFilterAuthorizationMethodInterceptor();
|
||||
interceptor.setTemplateDefaults(new AnnotationTemplateExpressionDefaults());
|
||||
return interceptor;
|
||||
}
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
companion object {
|
||||
@Bean
|
||||
@Role(BeanDescription.ROLE_INFRASTRUCTURE)
|
||||
fun preFilter(): Advisor {
|
||||
val interceptor = PreFilterAuthorizationMethodInterceptor()
|
||||
interceptor.setTemplateDefaults(AnnotationTemplateExpressionDefaults)
|
||||
return interceptor
|
||||
}
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
=== Publish `AuthorizationAdvisor` instances instead of adding them in a `Customizer<AuthorizationAdvisorProxyFactory>`
|
||||
|
||||
While the ability to customize the `AuthorizationAdvisorProxyFactory` instance will remain in Spring Security 7, the ability to add advisors will be removed in favor of picking up published `AuthorizationAdvisor` beans.
|
||||
|
||||
If you are not calling `AuthorizationAdvisorProxyFactory#setAdvisors` or `AuthorizationAdvisorProxyFactory#addAdvisor`, you need do nothing.
|
||||
|
||||
If you are, publish the `AuthorizationAdvisor` bean instead and Spring Security will pick it up and apply it automatically.
|
||||
|
@ -123,3 +123,60 @@ In versions prior to 6.2, if you had a xref:servlet/configuration/java.adoc#jc-c
|
||||
However, starting from version 6.2, this method is deprecated and will be removed in 7.0 because it will no longer be possible to chain configurations using `.and()` once `.and()` is removed (see https://github.com/spring-projects/spring-security/issues/13067).
|
||||
Instead, it is recommended to use the new `.with(...)` method.
|
||||
For more information about how to use `.with(...)` please refer to the xref:servlet/configuration/java.adoc#jc-custom-dsls[Custom DSLs section].
|
||||
|
||||
== Use `dispatcherTypeMatchers` instead of `shouldFilterAllDispatcherTypes`
|
||||
|
||||
If you are permitting the ERROR dispatch, you may be using `shouldFilterAllDispatcherTypes(false)` in the `auhorizeHttpRequests` DSL:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
http
|
||||
.authorizeHttpRequests((authorize) -> authorize
|
||||
.shouldFilterAllDispatcherTypes(false)
|
||||
// ...
|
||||
)
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
http {
|
||||
authorizeHttpRequests {
|
||||
shouldFilterAllDispatcherTypes = false
|
||||
// ...
|
||||
}
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
In preparation for 7, change this to use `dispatcherTypeMatchers`:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
http
|
||||
.authorizHttpRequests((authorize) -> authorize
|
||||
.dispatcherTypeMatchers(DispatcherType.ERROR).permitAll()
|
||||
// ...
|
||||
)
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
http {
|
||||
authorizeHttpRequests {
|
||||
authorize(new DispatcherTypeRequestMatcher(DispatcherType.ERROR), permitAll())
|
||||
}
|
||||
}
|
||||
----
|
||||
======
|
||||
|
@ -170,3 +170,70 @@ fun jwtDecoder(): JwtDecoder {
|
||||
<2> - specify the list of validators you need, excluding `JwtTypeValidator`
|
||||
|
||||
For additional guidance, please see the xref:servlet/oauth2/resource-server/jwt.adoc#oauth2resourceserver-jwt-validation[JwtDecoder Validators] section in the reference.
|
||||
|
||||
== Opaque Token Credentials Will Be Encoded For You
|
||||
|
||||
In order to comply more closely with the Introspection RFC, Spring Security's opaque token support will encode the client id and secret before creating the authorization header.
|
||||
This change means you will no longer have to encode the client id and secret yourself.
|
||||
|
||||
If your client id or secret contain URL-unsafe characters, then you can prepare yourself for this change by doing the following:
|
||||
|
||||
=== Replace Usage of `introspectionClientCredentials`
|
||||
|
||||
Since Spring Security can now do the encoding for you, replace xref:servlet/oauth2/resource-server/opaque-token.adoc#oauth2resourceserver-opaque-introspectionuri-dsl[using `introspectionClientCredentials`] with publishing the following `@Bean`:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
OpaqueTokenIntrospector introspector() {
|
||||
return SpringOpaqueTokenIntrospector.withIntrospectionUri(introspectionUri)
|
||||
.clientId(unencodedClientId).clientSecret(unencodedClientSecret).build();
|
||||
}
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@Bean
|
||||
fun introspector(): OpaqueTokenIntrospector {
|
||||
return SpringOpaqueTokenIntrospector.withIntrospectionUri(introspectionUri)
|
||||
.clientId(unencodedClientId).clientSecret(unencodedClientSecret).build()
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
The above will be the default in 7.0.
|
||||
|
||||
If this setting gives you trouble or you cannot apply it for now, you can use the `RestOperations` constructor instead:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
OpaqueTokenIntrospector introspector() {
|
||||
RestTemplate rest = new RestTemplate();
|
||||
rest.addInterceptor(new BasicAuthenticationInterceptor(encodedClientId, encodedClientSecret));
|
||||
return new SpringOpaqueTokenIntrospector(introspectionUri, rest);
|
||||
}
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@Bean
|
||||
fun introspector(): OpaqueTokenIntrospector {
|
||||
val rest = RestTemplate()
|
||||
rest.addInterceptor(BasicAuthenticationInterceptor(encodedClientId, encodedClientSecret))
|
||||
return SpringOpaqueTokenIntrospector(introspectionUri, rest)
|
||||
}
|
||||
----
|
||||
======
|
||||
|
@ -1,5 +1,17 @@
|
||||
= Saml 2.0 Migrations
|
||||
|
||||
== Use OpenSAML 5 By Default
|
||||
|
||||
OpenSAML 4.x is no longer supported by the OpenSAML team.
|
||||
As such, Spring Security will default to using its `OpenSaml5` components in all cases.
|
||||
|
||||
If you want to see how well your application will respond to this, do the following:
|
||||
|
||||
1. Update your OpenSAML dependencies to 5.x
|
||||
2. If you are constructing an `OpenSaml4XXX` Spring Security component, change it to `OpenSaml5`.
|
||||
|
||||
If you cannot opt-in, then add the `opensaml-saml-api` and `opensaml-saml-impl` 4.x dependencies and exclude the 5.x dependencies from `spring-security-saml2-service-provider`.
|
||||
|
||||
== Continue Filter Chain When No Relying Party Found
|
||||
|
||||
In Spring Security 6, `Saml2WebSsoAuthenticationFilter` throws an exception when the request URI matches, but no relying party registration is found.
|
||||
@ -163,3 +175,230 @@ val responseValidator = ResponseValidator.withDefaults { responseToken: Response
|
||||
provider.setResponseValidator(responseValidator)
|
||||
----
|
||||
======
|
||||
|
||||
== `RelyingPartyRegistration` Improvements
|
||||
|
||||
`RelyingPartyRegistration` links metadata from a relying party to metadata from an asserting party.
|
||||
|
||||
To prepare for some improvements to the API, please take the following steps:
|
||||
|
||||
1. If you are mutating a registration by using `RelyingPartyRegistration#withRelyingPartyRegistration`, instead call `RelyingPartyRegistration#mutate`
|
||||
2. If you are providing or retrieving `AssertingPartyDetails`, use `getAssertingPartyMetadata` or `withAssertingPartyMetadata` instead.
|
||||
|
||||
== `OpenSaml5AuthenticationProvider` Improvements
|
||||
|
||||
Spring Security 7 will remove a handful of static factories from `OpenSaml5AuthenticationProvider` in favor of inner classes.
|
||||
These inner classes simplify customization of the response validator, the assertion validator, and the response authentication converter.
|
||||
|
||||
=== Response Validation
|
||||
|
||||
Instead of doing:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
OpenSaml5AuthenticationProvider saml2AuthenticationProvider() {
|
||||
OpenSaml5AuthenticationProvider saml2 = new OpenSaml5AuthenticationProvider();
|
||||
saml2.setResponseValidator((responseToken) -> OpenSamlAuthenticationProvider.createDefaultResponseValidator()
|
||||
.andThen((result) -> result
|
||||
.concat(myCustomValidator.convert(responseToken))
|
||||
));
|
||||
return saml2;
|
||||
}
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@Bean
|
||||
fun saml2AuthenticationProvider(): OpenSaml5AuthenticationProvider {
|
||||
val saml2 = OpenSaml5AuthenticationProvider()
|
||||
saml2.setResponseValidator { responseToken -> OpenSamlAuthenticationProvider.createDefaultResponseValidator()
|
||||
.andThen { result -> result
|
||||
.concat(myCustomValidator.convert(responseToken))
|
||||
}
|
||||
}
|
||||
return saml2
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
use `OpenSaml5AuthenticationProvider.ResponseValidator`:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
OpenSaml5AuthenticationProvider saml2AuthenticationProvider() {
|
||||
OpenSaml5AuthenticationProvider saml2 = new OpenSaml5AuthenticationProvider();
|
||||
saml2.setResponseValidator(ResponseValidator.withDefaults(myCustomValidator));
|
||||
return saml2;
|
||||
}
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@Bean
|
||||
fun saml2AuthenticationProvider(): OpenSaml5AuthenticationProvider {
|
||||
val saml2 = OpenSaml5AuthenticationProvider()
|
||||
saml2.setResponseValidator(ResponseValidator.withDefaults(myCustomValidator))
|
||||
return saml2
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
=== Assertion Validation
|
||||
|
||||
Instead of doing:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
OpenSaml5AuthenticationProvider saml2AuthenticationProvider() {
|
||||
OpenSaml5AuthenticationProvider saml2 = new OpenSaml5AuthenticationProvider();
|
||||
authenticationProvider.setAssertionValidator(OpenSaml5AuthenticationProvider
|
||||
.createDefaultAssertionValidatorWithParameters(assertionToken -> {
|
||||
Map<String, Object> params = new HashMap<>();
|
||||
params.put(CLOCK_SKEW, Duration.ofMinutes(10).toMillis());
|
||||
// ... other validation parameters
|
||||
return new ValidationContext(params);
|
||||
})
|
||||
);
|
||||
return saml2;
|
||||
}
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@Bean
|
||||
fun saml2AuthenticationProvider(): OpenSaml5AuthenticationProvider {
|
||||
val saml2 = OpenSaml5AuthenticationProvider()
|
||||
authenticationProvider.setAssertionValidator(OpenSaml5AuthenticationProvider
|
||||
.createDefaultAssertionValidatorWithParameters { ->
|
||||
val params = HashMap<String, Object>()
|
||||
params.put(CLOCK_SKEW, Duration.ofMinutes(10).toMillis())
|
||||
// ... other validation parameters
|
||||
return ValidationContext(params)
|
||||
}
|
||||
)
|
||||
return saml2
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
use `OpenSaml5AuthenticationProvider.AssertionValidator`:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
OpenSaml5AuthenticationProvider saml2AuthenticationProvider() {
|
||||
OpenSaml5AuthenticationProvider saml2 = new OpenSaml5AuthenticationProvider();
|
||||
Duration tenMinutes = Duration.ofMinutes(10);
|
||||
authenticationProvider.setAssertionValidator(AssertionValidator.builder().clockSkew(tenMinutes).build());
|
||||
return saml2;
|
||||
}
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@Bean
|
||||
fun saml2AuthenticationProvider(): OpenSaml5AuthenticationProvider {
|
||||
val saml2 = OpenSaml5AuthenticationProvider()
|
||||
val tenMinutes = Duration.ofMinutes(10)
|
||||
authenticationProvider.setAssertionValidator(AssertionValidator.builder().clockSkew(tenMinutes).build())
|
||||
return saml2
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
== Response Authentication Converter
|
||||
|
||||
Instead of doing:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
Converter<ResponseToken, Saml2Authentication> authenticationConverter() {
|
||||
return (responseToken) -> {
|
||||
Saml2Authentication authentication = OpenSaml5AutnenticationProvider.createDefaultResponseAuthenticationConverter()
|
||||
.convert(responseToken);
|
||||
// ... work with OpenSAML's Assertion object to extract the principal
|
||||
return new Saml2Authentication(myPrincipal, authentication.getSaml2Response(), authentication.getAuthorities());
|
||||
};
|
||||
}
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@Bean
|
||||
fun authenticationConverter(): Converter<ResponseToken, Saml2Authentication> {
|
||||
return { responseToken ->
|
||||
val authentication =
|
||||
OpenSaml5AutnenticationProvider.createDefaultResponseAuthenticationConverter().convert(responseToken)
|
||||
// ... work with OpenSAML's Assertion object to extract the principal
|
||||
return Saml2Authentication(myPrincipal, authentication.getSaml2Response(), authentication.getAuthorities())
|
||||
}
|
||||
}
|
||||
----
|
||||
======
|
||||
|
||||
use `OpenSaml5AuthenticationProvider.ResponseAuthenticationConverter`:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
@Bean
|
||||
ResponseAuthenticationConverter authenticationConverter() {
|
||||
ResponseAuthenticationConverter authenticationConverter = new ResponseAuthenticationConverter();
|
||||
authenticationConverter.setPrincipalNameConverter((assertion) -> {
|
||||
// ... work with OpenSAML's Assertion object to extract the principal
|
||||
});
|
||||
return authenticationConverter;
|
||||
}
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
@Bean
|
||||
fun authenticationConverter(): ResponseAuthenticationConverter {
|
||||
val authenticationConverter = ResponseAuthenticationConverter()
|
||||
authenticationConverter.setPrincipalNameConverter { assertion ->
|
||||
// ... work with OpenSAML's Assertion object to extract the principal
|
||||
}
|
||||
return authenticationConverter
|
||||
}
|
||||
----
|
||||
======
|
||||
|
@ -521,3 +521,49 @@ Xml::
|
||||
=====
|
||||
If you have several circumstances where HTTP is needed, consider using `OrRequestMatcher` to combine them into a single `RequestMatcher` instance.
|
||||
=====
|
||||
|
||||
== Use `setCookieCustomizer` instead of individual setters
|
||||
|
||||
In favor of a simpler API, `CookieCsrfTokenRepository#setCookieCustomizer` allows you to change any aspect of the cookie, replacing `setCookieHttpOnly`, `setCookieMaxAge`, `setSecure`, and `setCookieDomain`.
|
||||
|
||||
Change this:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
CookeCsrfTokenRepository csrf = CookeCsrfTokenRepository.withHttpOnlyFalse();
|
||||
csrf.setCookieMaxAge(86400)
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
val csrf = CookeCsrfTokenRepository.withHttpOnlyFalse()
|
||||
csrf.setCookieMaxAge(86400)
|
||||
----
|
||||
======
|
||||
|
||||
to this:
|
||||
|
||||
[tabs]
|
||||
======
|
||||
Java::
|
||||
+
|
||||
[source,java,role="primary"]
|
||||
----
|
||||
CookeCsrfTokenRepository csrf = CookeCsrfTokenRepository.withHttpOnlyFalse();
|
||||
csrf.setCookieCustomizer((c) -> c.maxAge(86400));
|
||||
----
|
||||
|
||||
Kotlin::
|
||||
+
|
||||
[source,kotlin,role="secondary"]
|
||||
----
|
||||
val csrf = CookeCsrfTokenRepository.withHttpOnlyFalse()
|
||||
csrf.setCookieCustomizer { -> it.maxAge(86400) }
|
||||
----
|
||||
======
|
||||
|
Loading…
x
Reference in New Issue
Block a user