Bläddra i källkod

Document how to customize OneTimeTokenService

Closes gh-15743
Marcus Hert Da Coregio 11 månader sedan
förälder
incheckning
6417eb7159
1 ändrade filer med 153 tillägg och 12 borttagningar
  1. 153 12
      docs/modules/ROOT/pages/servlet/authentication/onetimetoken.adoc

+ 153 - 12
docs/modules/ROOT/pages/servlet/authentication/onetimetoken.adoc

@@ -31,17 +31,19 @@ The One-Time Token Login works in two major steps.
 1. User requests a token by submitting their user identifier, usually the username, and the token is delivered to them, often as a Magic Link, via e-mail, SMS, etc.
 2. User submits the token to the one-time token login endpoint and, if valid, the user gets logged in.
 
-[[default-pages]]
-== Default Login Page and Default One-Time Token Submit Page
-
-The `oneTimeTokenLogin()` DSL can be used in conjunction with `formLogin()`, which will produce an additional One-Time Token Request Form in the xref:servlet/authentication/passwords/form.adoc[default generated login page].
-It will also set up the javadoc:org.springframework.security.web.authentication.ui.DefaultOneTimeTokenSubmitPageGeneratingFilter[] to generate a default One-Time Token submit page.
-
 In the following sections we will explore how to configure OTT Login for your needs.
 
+- <<default-pages,Understanding the integration with the default generated login page>>
 - <<sending-token-to-user,Sending the token to the user>>
 - <<changing-submit-page-url,Configuring the One-Time Token submit page>>
 - <<changing-generate-url,Changing the One-Time Token generate URL>>
+- <<customize-generate-consume-token,Customize how to generate and consume tokens>>
+
+[[default-pages]]
+== Default Login Page and Default One-Time Token Submit Page
+
+The `oneTimeTokenLogin()` DSL can be used in conjunction with `formLogin()`, which will produce an additional One-Time Token Request Form in the xref:servlet/authentication/passwords/form.adoc[default generated login page].
+It will also set up the javadoc:org.springframework.security.web.authentication.ui.DefaultOneTimeTokenSubmitPageGeneratingFilter[] to generate a default One-Time Token submit page.
 
 [[sending-token-to-user]]
 == Sending the Token to the User
@@ -63,7 +65,7 @@ Java::
 public class SecurityConfig {
 
     @Bean
-    public SecurityFilterChain filterChain(HttpSecurity http, MagicLinkGeneratedOneTimeTokenSuccessHandler magicLinkSender) {
+    public SecurityFilterChain filterChain(HttpSecurity http, MagicLinkGeneratedOneTimeTokenHandler magicLinkSender) {
         http
             // ...
             .formLogin(Customizer.withDefaults())
@@ -77,7 +79,7 @@ import org.springframework.mail.SimpleMailMessage;
 import org.springframework.mail.javamail.JavaMailSender;
 
 @Component <1>
-public class MagicLinkGeneratedOneTimeTokenSuccessHandler implements GeneratedOneTimeTokenHandler {
+public class MagicLinkGeneratedOneTimeTokenHandler implements GeneratedOneTimeTokenSuccessHandler {
 
     private final MailSender mailSender;
 
@@ -177,7 +179,7 @@ class PageController {
 ----
 ======
 
-<1> Make the `MagicLinkGeneratedOneTimeTokenSuccessHandler` a Spring bean
+<1> Make the `MagicLinkGeneratedOneTimeTokenHandler` a Spring bean
 <2> Create a login processing URL with the `token` as a query param
 <3> Retrieve the user's email based on the username
 <4> Use the `JavaMailSender` API to send the email to the user with the magic link
@@ -220,7 +222,7 @@ public class SecurityConfig {
 }
 
 @Component
-public class MagicLinkGeneratedOneTimeTokenSuccessHandler implements GeneratedOneTimeTokenHandler {
+public class MagicLinkGeneratedOneTimeTokenHandler implements GeneratedOneTimeTokenSuccessHandler {
     // ...
 }
 ----
@@ -284,7 +286,7 @@ public class SecurityConfig {
 }
 
 @Component
-public class MagicLinkGeneratedOneTimeTokenSuccessHandler implements GeneratedOneTimeTokenSuccessHandler {
+public class MagicLinkGeneratedOneTimeTokenHandler implements GeneratedOneTimeTokenSuccessHandler {
     // ...
 }
 ----
@@ -360,7 +362,7 @@ public class MyController {
 }
 
 @Component
-public class MagicLinkGeneratedOneTimeTokenSuccessHandler implements GeneratedOneTimeTokenSuccessHandler {
+public class MagicLinkGeneratedOneTimeTokenHandler implements GeneratedOneTimeTokenSuccessHandler {
     // ...
 }
 ----
@@ -405,4 +407,143 @@ class MagicLinkGeneratedOneTimeTokenSuccessHandler : GeneratedOneTimeTokenHandle
 ----
 ======
 
+[[customize-generate-consume-token]]
+== Customize How to Generate and Consume One-Time Tokens
+
+The interface that define the common operations for generating and consuming one-time tokens is the javadoc:org.springframework.security.authentication.ott.OneTimeTokenService[].
+Spring Security uses the javadoc:org.springframework.security.authentication.ott.InMemoryOneTimeTokenService[] as the default implementation of that interface, if none is provided.
+
+Some of the most common reasons to customize the `OneTimeTokenService` are, but not limited to:
+
+- Changing the one-time token expire time
+- Storing more information from the generate token request
+- Changing how the token value is created
+- Additional validation when consuming a one-time token
 
+There are two options to customize the `OneTimeTokenService`.
+One option is to provide it as a bean, so it can be automatically be picked-up by the `oneTimeTokenLogin()` DSL:
+
+.Passing the OneTimeTokenService as a Bean
+[tabs]
+======
+Java::
++
+[source,java,role="primary"]
+----
+@Configuration
+@EnableWebSecurity
+public class SecurityConfig {
+
+    @Bean
+    public SecurityFilterChain filterChain(HttpSecurity http) {
+        http
+            // ...
+            .formLogin(Customizer.withDefaults())
+            .oneTimeTokenLogin(Customizer.withDefaults());
+        return http.build();
+    }
+
+    @Bean
+    public OneTimeTokenService oneTimeTokenService() {
+        return new MyCustomOneTimeTokenService();
+    }
+
+}
+
+@Component
+public class MagicLinkGeneratedOneTimeTokenHandler implements GeneratedOneTimeTokenSuccessHandler {
+    // ...
+}
+----
+
+Kotlin::
++
+[source,kotlin,role="secondary"]
+----
+@Configuration
+@EnableWebSecurity
+class SecurityConfig {
+
+    @Bean
+    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
+        http {
+            //...
+            formLogin { }
+            oneTimeTokenLogin { }
+        }
+        return http.build()
+    }
+
+    @Bean
+    open fun oneTimeTokenService(): OneTimeTokenService {
+        return MyCustomOneTimeTokenService()
+    }
+}
+
+@Component
+class MagicLinkGeneratedOneTimeTokenSuccessHandler : GeneratedOneTimeTokenHandler {
+     // ...
+}
+----
+======
+
+The second option is to pass the `OneTimeTokenService` instance to the DSL, which is useful if there are multiple `SecurityFilterChain` and a different `OneTimeTokenService` is needed for each of them.
+
+.Passing the OneTimeTokenService using the DSL
+[tabs]
+======
+Java::
++
+[source,java,role="primary"]
+----
+@Configuration
+@EnableWebSecurity
+public class SecurityConfig {
+
+    @Bean
+    public SecurityFilterChain filterChain(HttpSecurity http) {
+        http
+            // ...
+            .formLogin(Customizer.withDefaults())
+            .oneTimeTokenLogin((ott) -> ott
+                .oneTimeTokenService(new MyCustomOneTimeTokenService())
+            );
+        return http.build();
+    }
+
+}
+
+@Component
+public class MagicLinkGeneratedOneTimeTokenHandler implements GeneratedOneTimeTokenSuccessHandler {
+    // ...
+}
+----
+
+Kotlin::
++
+[source,kotlin,role="secondary"]
+----
+@Configuration
+@EnableWebSecurity
+class SecurityConfig {
+
+    @Bean
+    open fun filterChain(http: HttpSecurity): SecurityFilterChain {
+        http {
+            //...
+            formLogin { }
+            oneTimeTokenLogin {
+                oneTimeTokenService = MyCustomOneTimeTokenService()
+            }
+        }
+        return http.build()
+    }
+
+}
+
+@Component
+class MagicLinkGeneratedOneTimeTokenSuccessHandler : GeneratedOneTimeTokenHandler {
+     // ...
+}
+----
+======