I have two secured areas for which I provide form-based logins.
/user/admin
The following works as expected:
- Redirecting to Login-Page when accessing protected resource
- Redirecting to Login-Page with an
?errorparam when credentials were false - Preventing access to protected resource based on roles defined
The following does not work:
- Redirecting to Login-Page after logging out
When logging out, I redirect to /user/login?logout in order to display a message 'You'e logged out' indicating that logout was successful. However, that does not work, instead the redirect to /user/login?logout is being redirected to /user/login and thus no message is shown.
When I remove the custom logout-handler .logoutSuccessHandler(logoutSuccessHandler()), and instead include the .logoutSuccessUrl("/user/login?logout").permitAll() it works!
However I want this handler to perform additional actions when logging out.
@Configuration
@Order(1)
public static class FormLoginUser extends WebSecurityConfigurerAdapter {
@Bean
public AccessDeniedHandler accessDeniedHandler() {
return new UserCustomAccessDeniedHandler();
}
@Bean
public LogoutSuccessHandler logoutSuccessHandler() {
return new UserCustomLogoutSuccessHandler();
}
@Bean
public AuthenticationSuccessHandler authenticationSuccessHandler() {
return new UserCustomAuthenticationSuccessHandler();
}
private AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> authenticationDetailsSource() {
return WebAuthenticationDetails::new;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/user/**")
.authorizeRequests().anyRequest().hasRole("USER")
.and()
.formLogin()
.loginPage("/user/login")
.permitAll()
.authenticationDetailsSource(authenticationDetailsSource())
.successHandler(authenticationSuccessHandler())
.and()
.logout()
.logoutUrl("/user/logout")
.logoutSuccessUrl("/user/login?logout").permitAll()
.logoutSuccessHandler(logoutSuccessHandler())
.and()
.exceptionHandling().accessDeniedHandler(accessDeniedHandler())
;
}
}
@Configuration
@Order(2)
public static class FormLoginAdmin extends WebSecurityConfigurerAdapter {
@Bean
public AccessDeniedHandler adminAccessDeniedHandler() {
return new AdminCustomAccessDeniedHandler();
}
@Bean
public LogoutSuccessHandler adminLogoutSuccessHandler() {
return new AdminCustomLogoutSuccessHandler();
}
@Bean
public AuthenticationSuccessHandler adminAuthenticationSuccessHandler() {
return new AdminCustomAuthenticationSuccessHandler();
}
private AuthenticationDetailsSource<HttpServletRequest, WebAuthenticationDetails> authenticationDetailsSource() {
return WebAuthenticationDetails::new;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.antMatcher("/admin/**")
.authorizeRequests().anyRequest().hasRole("ADMIN")
.and()
.formLogin()
.loginPage("/admin/login")
.authenticationDetailsSource(authenticationDetailsSource())
.successHandler(adminAuthenticationSuccessHandler())
.permitAll()
.and()
.logout()
.logoutUrl("/admin/logout")
.logoutSuccessHandler(adminLogoutSuccessHandler())
.and()
.exceptionHandling().accessDeniedHandler(adminAccessDeniedHandler());
}
}
Here is my CustomLogoutHandler:
public class UserCustomLogoutSuccessHandler extends
SimpleUrlLogoutSuccessHandler implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(
HttpServletRequest request,
HttpServletResponse response,
Authentication authentication)
throws IOException, ServletException {
this.setDefaultTargetUrl("/user/login?logout");
super.onLogoutSuccess(request, response, authentication);
}
}
In the DevTools, I can clearly see, whenever I try to access the URL /user/login?logout the GET-Request results in 302 and then a new request is made for user/login. That happens when I manually edit the URL in the browser URL line or when triggering the logout via FORM-Post from the application.
When I remove the logoutSuccessHandler I can both, enter the URL in the browser manually and trigger it form my FORM-Post in the application.
I also tried:
- moving the URLs for login and logout out of the path
/user-> that broke the Login - defining a third configuration with
Order(1)explicitly allowing GET and POST on the login and logout-pages -> that as well broke the Login - not use
.antMatcherand use.antMatchersinstead, however then I think I won't be able to have two different FormLogins