21
21
import java .util .Collections ;
22
22
import java .util .Map ;
23
23
import java .util .function .Function ;
24
+ import java .util .stream .Collectors ;
24
25
25
26
import jakarta .servlet .FilterChain ;
26
27
import jakarta .servlet .ServletException ;
33
34
import org .springframework .util .Assert ;
34
35
import org .springframework .util .StringUtils ;
35
36
import org .springframework .web .filter .OncePerRequestFilter ;
36
- import org .springframework .web .util .HtmlUtils ;
37
37
38
38
/**
39
39
* Creates a default one-time token submit page. If the request contains a {@code token}
@@ -65,54 +65,27 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse
65
65
66
66
private String generateHtml (HttpServletRequest request ) {
67
67
String token = request .getParameter ("token" );
68
- String inputValue = StringUtils .hasText (token ) ? HtmlUtils .htmlEscape (token ) : "" ;
69
- String input = "<input type=\" text\" id=\" token\" name=\" token\" value=\" " + inputValue + "\" "
70
- + " placeholder=\" Token\" required=\" true\" autofocus=\" autofocus\" />" ;
71
- return """
72
- <!DOCTYPE html>
73
- <html lang="en">
74
- <head>
75
- <title>One-Time Token Login</title>
76
- <meta charset="utf-8"/>
77
- <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
78
- <meta http-equiv="Content-Security-Policy" content="script-src 'sha256-oZhLbc2kO8b8oaYLrUc7uye1MgVKMyLtPqWR4WtKF+c='"/>
79
- """
80
- + CssUtils .getCssStyleBlock ().indent (4 )
81
- + """
82
- </head>
83
- <body>
84
- <noscript>
85
- <p>
86
- <strong>Note:</strong> Since your browser does not support JavaScript, you must press the Sign In button once to proceed.
87
- </p>
88
- </noscript>
89
- <div class="container">
90
- """
91
- + "<form class=\" login-form\" action=\" " + this .loginProcessingUrl + "\" method=\" post\" >" + """
92
- <h2>Please input the token</h2>
93
- <p>
94
- <label for="token" class="screenreader">Token</label>
95
- """ + input + """
96
- </p>
97
- <button class="primary" type="submit">Sign in</button>
98
- """ + renderHiddenInputs (request ) + """
99
- </form>
100
- </div>
101
- </body>
102
- </html>
103
- """ ;
68
+ String tokenValue = StringUtils .hasText (token ) ? token : "" ;
69
+
70
+ String hiddenInputs = this .resolveHiddenInputs .apply (request )
71
+ .entrySet ()
72
+ .stream ()
73
+ .map ((inputKeyValue ) -> renderHiddenInput (inputKeyValue .getKey (), inputKeyValue .getValue ()))
74
+ .collect (Collectors .joining ("\n " ));
75
+
76
+ return HtmlTemplates .fromTemplate (ONE_TIME_TOKEN_SUBMIT_PAGE_TEMPLATE )
77
+ .withRawHtml ("cssStyle" , CssUtils .getCssStyleBlock ().indent (4 ))
78
+ .withValue ("tokenValue" , tokenValue )
79
+ .withValue ("loginProcessingUrl" , this .loginProcessingUrl )
80
+ .withRawHtml ("hiddenInputs" , hiddenInputs )
81
+ .render ();
104
82
}
105
83
106
- private String renderHiddenInputs (HttpServletRequest request ) {
107
- StringBuilder sb = new StringBuilder ();
108
- for (Map .Entry <String , String > input : this .resolveHiddenInputs .apply (request ).entrySet ()) {
109
- sb .append ("<input name=\" " );
110
- sb .append (input .getKey ());
111
- sb .append ("\" type=\" hidden\" value=\" " );
112
- sb .append (input .getValue ());
113
- sb .append ("\" />\n " );
114
- }
115
- return sb .toString ();
84
+ private String renderHiddenInput (String name , String value ) {
85
+ return HtmlTemplates .fromTemplate (HIDDEN_HTML_INPUT_TEMPLATE )
86
+ .withValue ("name" , name )
87
+ .withValue ("value" , value )
88
+ .render ();
116
89
}
117
90
118
91
public void setResolveHiddenInputs (Function <HttpServletRequest , Map <String , String >> resolveHiddenInputs ) {
@@ -135,4 +108,39 @@ public void setLoginProcessingUrl(String loginProcessingUrl) {
135
108
this .loginProcessingUrl = loginProcessingUrl ;
136
109
}
137
110
111
+ private static final String ONE_TIME_TOKEN_SUBMIT_PAGE_TEMPLATE = """
112
+ <!DOCTYPE html>
113
+ <html lang="en">
114
+ <head>
115
+ <title>One-Time Token Login</title>
116
+ <meta charset="utf-8"/>
117
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"/>
118
+ <meta http-equiv="Content-Security-Policy" content="script-src 'sha256-oZhLbc2kO8b8oaYLrUc7uye1MgVKMyLtPqWR4WtKF+c='"/>
119
+ {{cssStyle}}
120
+ </head>
121
+ <body>
122
+ <noscript>
123
+ <p>
124
+ <strong>Note:</strong> Since your browser does not support JavaScript, you must press the Sign In button once to proceed.
125
+ </p>
126
+ </noscript>
127
+ <div class="container">
128
+ <form class="login-form" action="{{loginProcessingUrl}}" method="post">
129
+ <h2>Please input the token</h2>
130
+ <p>
131
+ <label for="token" class="screenreader">Token</label>
132
+ <input type="text" id="token" name="token" value="{{tokenValue}}" placeholder="Token" required="true" autofocus="autofocus"/>
133
+ </p>
134
+ <button class="primary" type="submit">Sign in</button>
135
+ {{hiddenInputs}}
136
+ </form>
137
+ </div>
138
+ </body>
139
+ </html>
140
+ """ ;
141
+
142
+ private static final String HIDDEN_HTML_INPUT_TEMPLATE = """
143
+ <input name="{{name}}" type="hidden" value="{{value}}" />
144
+ """ ;
145
+
138
146
}
0 commit comments