19
19
import java .nio .charset .Charset ;
20
20
import java .util .HashMap ;
21
21
import java .util .Map ;
22
+ import java .util .stream .Collectors ;
22
23
23
24
import reactor .core .publisher .Mono ;
24
25
37
38
import org .springframework .web .server .ServerWebExchange ;
38
39
import org .springframework .web .server .WebFilter ;
39
40
import org .springframework .web .server .WebFilterChain ;
40
- import org .springframework .web .util .HtmlUtils ;
41
41
42
42
/**
43
43
* Generates a default log in page used for authenticating users.
@@ -89,80 +89,61 @@ private Mono<DataBuffer> createBuffer(ServerWebExchange exchange) {
89
89
private byte [] createPage (ServerWebExchange exchange , String csrfTokenHtmlInput ) {
90
90
MultiValueMap <String , String > queryParams = exchange .getRequest ().getQueryParams ();
91
91
String contextPath = exchange .getRequest ().getPath ().contextPath ().value ();
92
- StringBuilder page = new StringBuilder ();
93
- page .append ("<!DOCTYPE html>\n " );
94
- page .append ("<html lang=\" en\" >\n " );
95
- page .append (" <head>\n " );
96
- page .append (" <meta charset=\" utf-8\" >\n " );
97
- page .append (" <meta name=\" viewport\" content=\" width=device-width, initial-scale=1, shrink-to-fit=no\" >\n " );
98
- page .append (" <meta name=\" description\" content=\" \" >\n " );
99
- page .append (" <meta name=\" author\" content=\" \" >\n " );
100
- page .append (" <title>Please sign in</title>\n " );
101
- page .append (CssUtils .getCssStyleBlock ().indent (4 ));
102
- page .append (" </head>\n " );
103
- page .append (" <body>\n " );
104
- page .append (" <div class=\" content\" >\n " );
105
- page .append (formLogin (queryParams , contextPath , csrfTokenHtmlInput ));
106
- page .append (oauth2LoginLinks (queryParams , contextPath , this .oauth2AuthenticationUrlToClientName ));
107
- page .append (" </div>\n " );
108
- page .append (" </body>\n " );
109
- page .append ("</html>" );
110
- return page .toString ().getBytes (Charset .defaultCharset ());
92
+
93
+ return HtmlTemplates .fromTemplate (LOGIN_PAGE_TEMPLATE )
94
+ .withRawHtml ("cssStyle" , CssUtils .getCssStyleBlock ().indent (4 ))
95
+ .withRawHtml ("formLogin" , formLogin (queryParams , contextPath , csrfTokenHtmlInput ))
96
+ .withRawHtml ("oauth2Login" , oauth2Login (queryParams , contextPath , this .oauth2AuthenticationUrlToClientName ))
97
+ .render ()
98
+ .getBytes (Charset .defaultCharset ());
111
99
}
112
100
113
101
private String formLogin (MultiValueMap <String , String > queryParams , String contextPath , String csrfTokenHtmlInput ) {
114
102
if (!this .formLoginEnabled ) {
115
103
return "" ;
116
104
}
105
+
117
106
boolean isError = queryParams .containsKey ("error" );
118
107
boolean isLogoutSuccess = queryParams .containsKey ("logout" );
119
- StringBuilder page = new StringBuilder ();
120
- page .append (" <form class=\" login-form\" method=\" post\" action=\" " + contextPath + "/login\" >\n " );
121
- page .append (" <h2>Please sign in</h2>\n " );
122
- page .append (createError (isError ));
123
- page .append (createLogoutSuccess (isLogoutSuccess ));
124
- page .append (" <p>\n " );
125
- page .append (" <label for=\" username\" class=\" screenreader\" >Username</label>\n " );
126
- page .append (" <input type=\" text\" id=\" username\" name=\" username\" "
127
- + "placeholder=\" Username\" required autofocus>\n " );
128
- page .append (" </p>\n " + " <p>\n " );
129
- page .append (" <label for=\" password\" class=\" screenreader\" >Password</label>\n " );
130
- page .append (" <input type=\" password\" id=\" password\" name=\" password\" "
131
- + "placeholder=\" Password\" required>\n " );
132
- page .append (" </p>\n " );
133
- page .append (csrfTokenHtmlInput );
134
- page .append (" <button class=\" primary\" type=\" submit\" >Sign in</button>\n " );
135
- page .append (" </form>\n " );
136
- return page .toString ();
108
+
109
+ return HtmlTemplates .fromTemplate (LOGIN_FORM_TEMPLATE )
110
+ .withValue ("loginUrl" , contextPath + "/login" )
111
+ .withRawHtml ("errorMessage" , createError (isError ))
112
+ .withRawHtml ("logoutMessage" , createLogoutSuccess (isLogoutSuccess ))
113
+ .withRawHtml ("csrf" , csrfTokenHtmlInput )
114
+ .render ();
137
115
}
138
116
139
- private static String oauth2LoginLinks (MultiValueMap <String , String > queryParams , String contextPath ,
117
+ private static String oauth2Login (MultiValueMap <String , String > queryParams , String contextPath ,
140
118
Map <String , String > oauth2AuthenticationUrlToClientName ) {
141
119
if (oauth2AuthenticationUrlToClientName .isEmpty ()) {
142
120
return "" ;
143
121
}
144
122
boolean isError = queryParams .containsKey ("error" );
145
- StringBuilder sb = new StringBuilder ();
146
- sb .append ("<div class=\" content\" ><h2>Login with OAuth 2.0</h2>" );
147
- sb .append (createError (isError ));
148
- sb .append ("<table class=\" table table-striped\" >\n " );
149
- for (Map .Entry <String , String > clientAuthenticationUrlToClientName : oauth2AuthenticationUrlToClientName
150
- .entrySet ()) {
151
- sb .append (" <tr><td>" );
152
- String url = clientAuthenticationUrlToClientName .getKey ();
153
- sb .append ("<a href=\" " ).append (contextPath ).append (url ).append ("\" >" );
154
- String clientName = HtmlUtils .htmlEscape (clientAuthenticationUrlToClientName .getValue ());
155
- sb .append (clientName );
156
- sb .append ("</a>" );
157
- sb .append ("</td></tr>\n " );
158
- }
159
- sb .append ("</table></div>\n " );
160
- return sb .toString ();
123
+
124
+ String oauth2Rows = oauth2AuthenticationUrlToClientName .entrySet ()
125
+ .stream ()
126
+ .map ((urlToName ) -> oauth2LoginLink (contextPath , urlToName .getKey (), urlToName .getValue ()))
127
+ .collect (Collectors .joining ("\n " ))
128
+ .indent (2 );
129
+ return HtmlTemplates .fromTemplate (OAUTH2_LOGIN_TEMPLATE )
130
+ .withRawHtml ("errorMessage" , createError (isError ))
131
+ .withRawHtml ("oauth2Rows" , oauth2Rows )
132
+ .render ();
133
+ }
134
+
135
+ private static String oauth2LoginLink (String contextPath , String url , String clientName ) {
136
+ return HtmlTemplates .fromTemplate (OAUTH2_ROW_TEMPLATE )
137
+ .withValue ("url" , contextPath + url )
138
+ .withValue ("clientName" , clientName )
139
+ .render ();
161
140
}
162
141
163
142
private static String csrfToken (CsrfToken token ) {
164
- return " <input type=\" hidden\" name=\" " + token .getParameterName () + "\" value=\" " + token .getToken ()
165
- + "\" >\n " ;
143
+ return HtmlTemplates .fromTemplate (CSRF_INPUT_TEMPLATE )
144
+ .withValue ("name" , token .getParameterName ())
145
+ .withValue ("value" , token .getToken ())
146
+ .render ();
166
147
}
167
148
168
149
private static String createError (boolean isError ) {
@@ -174,4 +155,53 @@ private static String createLogoutSuccess(boolean isLogoutSuccess) {
174
155
: "" ;
175
156
}
176
157
158
+ private static final String LOGIN_PAGE_TEMPLATE = """
159
+ <!DOCTYPE html>
160
+ <html lang="en">
161
+ <head>
162
+ <meta charset="utf-8">
163
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
164
+ <meta name="description" content="">
165
+ <meta name="author" content="">
166
+ <title>Please sign in</title>
167
+ {{cssStyle}}
168
+ </head>
169
+ <body>
170
+ <div class="content">
171
+ {{formLogin}}
172
+ {{oauth2Login}}
173
+ </div>
174
+ </body>
175
+ </html>""" ;
176
+
177
+ private static final String LOGIN_FORM_TEMPLATE = """
178
+ <form class="login-form" method="post" action="{{loginUrl}}">
179
+ <h2>Please sign in</h2>
180
+ {{errorMessage}}{{logoutMessage}}
181
+ <p>
182
+ <label for="username" class="screenreader">Username</label>
183
+ <input type="text" id="username" name="username" placeholder="Username" required autofocus>
184
+ </p>
185
+ <p>
186
+ <label for="password" class="screenreader">Password</label>
187
+ <input type="password" id="password" name="password" placeholder="Password" required>
188
+ </p>
189
+ {{csrf}}
190
+ <button type="submit" class="primary">Sign in</button>
191
+ </form>""" ;
192
+
193
+ private static final String CSRF_INPUT_TEMPLATE = """
194
+ <input name="{{name}}" type="hidden" value="{{value}}" />
195
+ """ ;
196
+
197
+ private static final String OAUTH2_LOGIN_TEMPLATE = """
198
+ <h2>Login with OAuth 2.0</h2>
199
+ {{errorMessage}}
200
+ <table class="table table-striped">
201
+ {{oauth2Rows}}
202
+ </table>""" ;
203
+
204
+ private static final String OAUTH2_ROW_TEMPLATE = """
205
+ <tr><td><a href="{{url}}">{{clientName}}</a></td></tr>""" ;
206
+
177
207
}
0 commit comments