从 CustomLogoutHandler 重定向到 'login?logout' 被重定向到 'login'
Posted
技术标签:
【中文标题】从 CustomLogoutHandler 重定向到 \'login?logout\' 被重定向到 \'login\'【英文标题】:Redirect from CustomLogoutHandler to 'login?logout' is redirected to 'login'从 CustomLogoutHandler 重定向到 'login?logout' 被重定向到 'login' 【发布时间】:2020-02-08 19:16:46 【问题描述】:我有两个安全区域,我为其提供基于表单的登录。
/user
/admin
以下按预期工作:
访问受保护资源时重定向到登录页面 当凭据为假时,使用?error
参数重定向到登录页面
根据定义的角色阻止对受保护资源的访问
以下不起作用:
注销后重定向到登录页面注销时,我重定向到/user/login?logout
以显示一条消息“您已注销”,表明注销成功。但是,这不起作用,而是重定向到 /user/login?logout
被重定向到 /user/login
,因此没有显示任何消息。
当我删除自定义注销处理程序 .logoutSuccessHandler(logoutSuccessHandler())
并包含 .logoutSuccessUrl("/user/login?logout").permitAll()
时,它可以工作!
但我希望此处理程序在注销时执行其他操作。
@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());
这是我的 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);
在 DevTools 中,我可以清楚地看到,每当我尝试访问 URL /user/login?logout
时,GET-Request 结果为 302,然后对 user/login
发出新请求。当我在浏览器 URL 行中手动编辑 URL 或通过应用程序中的 FORM-Post 触发注销时,就会发生这种情况。
当我删除 logoutSuccessHandler
时,我可以在浏览器中手动输入 URL,并在应用程序中的 FORM-Post 中触发它。
我也试过了:
将登录和注销 URL 移出路径/user
-> 破坏登录
使用Order(1)
定义第三个配置,明确允许在登录和注销页面上进行 GET 和 POST -> 这也破坏了登录
不要使用.antMatcher
而是使用.antMatchers
,但是我想我将无法拥有两个不同的FormLogins
【问题讨论】:
【参考方案1】:我知道这种类型的问题会打上一个大大的问号,让人想为什么会摸不着头脑?
解决方案是。
@Override
protected void configure(HttpSecurity http) throws Exception
http
.antMatcher("/user/**").authorizeRequests()
.antMatchers("/user/login").permitAll() //solution
.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());
想知道为什么?
根据之前的配置您的资源/user/login
是受限资源,只有在authenticated = true
和hasRole = "User"
时才被允许
在您的注销成功处理程序中,您正在使会话无效并重定向到 /user/login?logout
页面,但 /user/login
是受限制的资源,因此 FilterSecurityInterceptor
将重定向到配置的登录页面(.loginPage("/user/login")
。因此您将不会收到任何传入查询的参数字符串。
因此解决方案将始终将登录页面设置为不受限制的资源。
【讨论】:
以上是关于从 CustomLogoutHandler 重定向到 'login?logout' 被重定向到 'login'的主要内容,如果未能解决你的问题,请参考以下文章