2121import java .util .Collections ;
2222import java .util .Map ;
2323import java .util .function .Function ;
24+ import java .util .stream .Collectors ;
2425
2526import jakarta .servlet .FilterChain ;
2627import jakarta .servlet .ServletException ;
3334import org .springframework .util .Assert ;
3435import org .springframework .util .StringUtils ;
3536import org .springframework .web .filter .OncePerRequestFilter ;
36- import org .springframework .web .util .HtmlUtils ;
3737
3838/**
3939 * 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
6565
6666 private String generateHtml (HttpServletRequest request ) {
6767 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 ();
10482 }
10583
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 ();
11689 }
11790
11891 public void setResolveHiddenInputs (Function <HttpServletRequest , Map <String , String >> resolveHiddenInputs ) {
@@ -135,4 +108,39 @@ public void setLoginProcessingUrl(String loginProcessingUrl) {
135108 this .loginProcessingUrl = loginProcessingUrl ;
136109 }
137110
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+
138146}
0 commit comments