1
1
package eu .solven .kumite .account .login ;
2
2
3
+ import java .net .URI ;
4
+
3
5
import org .springframework .boot .autoconfigure .web .ServerProperties ;
4
6
import org .springframework .context .annotation .Bean ;
5
7
import org .springframework .context .annotation .Import ;
15
17
import org .springframework .security .oauth2 .server .resource .web .server .BearerTokenServerAuthenticationEntryPoint ;
16
18
import org .springframework .security .web .server .SecurityWebFilterChain ;
17
19
import org .springframework .security .web .server .authentication .RedirectServerAuthenticationSuccessHandler ;
20
+ import org .springframework .security .web .server .authentication .logout .RedirectServerLogoutSuccessHandler ;
21
+ import org .springframework .security .web .server .csrf .WebSessionServerCsrfTokenRepository ;
18
22
import org .springframework .security .web .server .util .matcher .ServerWebExchangeMatchers ;
19
23
20
24
import com .nimbusds .jwt .JWT ;
@@ -56,6 +60,10 @@ public SecurityWebFilterChain configureUi(ServerProperties serverProperties,
56
60
// provider
57
61
"/api/login/v1/**" ,
58
62
"/oauth2/**" ,
63
+
64
+ // The logout route (do a POST to logout, i.e. clear the session)
65
+ "/logout" ,
66
+
59
67
// Holds static resources (e.g. `/ui/js/store.js`)
60
68
"/ui/js/**" ,
61
69
"/ui/img/**" ,
@@ -69,6 +77,17 @@ public SecurityWebFilterChain configureUi(ServerProperties serverProperties,
69
77
"/swagger-ui.html" ,
70
78
"/swagger-ui/**" ,
71
79
"/webjars/**" ))
80
+
81
+ .csrf (csrf -> {
82
+ csrf
83
+ // https://docs.spring.io/spring-security/reference/reactive/exploits/csrf.html#webflux-csrf-configure-custom-repository
84
+ // .csrfTokenRepository(CookieServerCsrfTokenRepository.withHttpOnlyFalse())
85
+
86
+ // This will NOT provide the CSRF as a header: `X-CSRF-TOKEN`
87
+ // But it wlll help making it available on `/api/login/v1/csrf`
88
+ .csrfTokenRepository (new WebSessionServerCsrfTokenRepository ());
89
+ })
90
+
72
91
.authorizeExchange (auth -> auth
73
92
74
93
// Login does not requires being loggged-in yet
@@ -78,9 +97,11 @@ public SecurityWebFilterChain configureUi(ServerProperties serverProperties,
78
97
// Swagger UI
79
98
.pathMatchers ("/swagger-ui.html" , "/swagger-ui/**" )
80
99
.permitAll ()
81
- // The route used by the SPA
100
+
101
+ // The route used by the SPA: they all serve index.html
82
102
.pathMatchers ("/" , "/html/**" )
83
103
.permitAll ()
104
+
84
105
// Webjars and static resources
85
106
.pathMatchers ("/ui/js/**" , "/ui/img/**" , "/webjars/**" , "/favicon.ico" )
86
107
.permitAll ()
@@ -90,7 +111,9 @@ public SecurityWebFilterChain configureUi(ServerProperties serverProperties,
90
111
.pathMatchers ("/api/login/v1/user" ,
91
112
"/api/login/v1/oauth2/token" ,
92
113
"/api/login/v1/html" ,
93
- "/api/login/v1/providers" )
114
+ "/api/login/v1/providers" ,
115
+ "/api/login/v1/csrf" ,
116
+ "/api/login/v1/logout" )
94
117
.permitAll ()
95
118
96
119
// The rest needs to be authenticated
@@ -99,7 +122,7 @@ public SecurityWebFilterChain configureUi(ServerProperties serverProperties,
99
122
100
123
// `/html/login` has to be synced with the SPA login route
101
124
.formLogin (login -> {
102
- String loginPage = ( "http%s://localhost:8080" + "/ html/login") .formatted (isSsl ? "s" : "" );
125
+ String loginPage = "/ html/login" .formatted (isSsl ? "s" : "" );
103
126
login .loginPage (loginPage )
104
127
// Required not to get an NPE at `.build()`
105
128
.authenticationManager (ram );
@@ -108,11 +131,17 @@ public SecurityWebFilterChain configureUi(ServerProperties serverProperties,
108
131
// https://docs.spring.io/spring-security/reference/servlet/oauth2/client/authorization-grants.html
109
132
// https://stackoverflow.com/questions/74242738/how-to-logout-from-oauth-signed-in-web-app-with-github
110
133
.oauth2Login (oauth2 -> {
111
- String loginSuccess =
112
- ("http%s://localhost:8080" + "/html/login?success" ).formatted (isSsl ? "s" : "" );
134
+ String loginSuccess = "/html/login?success" .formatted (isSsl ? "s" : "" );
113
135
oauth2 .authenticationSuccessHandler (new RedirectServerAuthenticationSuccessHandler (loginSuccess ));
114
136
})
115
137
138
+ .logout (logout -> {
139
+ RedirectServerLogoutSuccessHandler logoutSuccessHandler = new RedirectServerLogoutSuccessHandler ();
140
+ // We need to redirect to a 2XX URL, and not a 3XX URL, as Fetch API can not intercept redirections.
141
+ logoutSuccessHandler .setLogoutSuccessUrl (URI .create ("/api/login/v1/logout" ));
142
+ logout .logoutSuccessHandler (logoutSuccessHandler );
143
+ })
144
+
116
145
.build ();
117
146
}
118
147
0 commit comments