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,60 @@ 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 ())
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
+ return HtmlTemplates . fromTemplate ( OAUTH2_LOGIN_TEMPLATE )
129
+ . withRawHtml ( "errorMessage" , createError ( isError ))
130
+ . withRawHtml ( "oauth2Rows" , oauth2Rows )
131
+ . render ( );
132
+ }
133
+
134
+ private static String oauth2LoginLink ( String contextPath , String url , String clientName ) {
135
+ return HtmlTemplates . fromTemplate ( OAUTH2_ROW_TEMPLATE )
136
+ . withValue ( "url" , contextPath + url )
137
+ . withValue ( "clientName" , clientName )
138
+ . render ();
161
139
}
162
140
163
141
private static String csrfToken (CsrfToken token ) {
164
- return " <input type=\" hidden\" name=\" " + token .getParameterName () + "\" value=\" " + token .getToken ()
165
- + "\" >\n " ;
142
+ return HtmlTemplates .fromTemplate (CSRF_INPUT_TEMPLATE )
143
+ .withValue ("name" , token .getParameterName ())
144
+ .withValue ("value" , token .getToken ())
145
+ .render ();
166
146
}
167
147
168
148
private static String createError (boolean isError ) {
@@ -174,4 +154,53 @@ private static String createLogoutSuccess(boolean isLogoutSuccess) {
174
154
: "" ;
175
155
}
176
156
157
+ private static final String LOGIN_PAGE_TEMPLATE = """
158
+ <!DOCTYPE html>
159
+ <html lang="en">
160
+ <head>
161
+ <meta charset="utf-8">
162
+ <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
163
+ <meta name="description" content="">
164
+ <meta name="author" content="">
165
+ <title>Please sign in</title>
166
+ {{cssStyle}}
167
+ </head>
168
+ <body>
169
+ <div class="content">
170
+ {{formLogin}}
171
+ {{oauth2Login}}
172
+ </div>
173
+ </body>
174
+ </html>""" ;
175
+
176
+ private static final String LOGIN_FORM_TEMPLATE = """
177
+ <form class="login-form" method="post" action="{{loginUrl}}">
178
+ <h2>Please sign in</h2>
179
+ {{errorMessage}}{{logoutMessage}}
180
+ <p>
181
+ <label for="username" class="screenreader">Username</label>
182
+ <input type="text" id="username" name="username" placeholder="Username" required autofocus>
183
+ </p>
184
+ <p>
185
+ <label for="password" class="screenreader">Password</label>
186
+ <input type="password" id="password" name="password" placeholder="Password" required>
187
+ </p>
188
+ {{csrf}}
189
+ <button type="submit" class="primary">Sign in</button>
190
+ </form>""" ;
191
+
192
+ private static final String CSRF_INPUT_TEMPLATE = """
193
+ <input name="{{name}}" type="hidden" value="{{value}}" />
194
+ """ ;
195
+
196
+ private static final String OAUTH2_LOGIN_TEMPLATE = """
197
+ <h2>Login with OAuth 2.0</h2>
198
+ {{errorMessage}}
199
+ <table class="table table-striped">
200
+ {{oauth2Rows}}
201
+ </table>""" ;
202
+
203
+ private static final String OAUTH2_ROW_TEMPLATE = """
204
+ \t <tr><td><a href="{{url}}">{{clientName}}</a></td></tr>""" ;
205
+
177
206
}
0 commit comments