我有两个安全的区域,我为其提供基于表单的登录。
/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中触发它。
我也尝试过:
/user
->破坏登录的路径Order(1)
定义第三种配置,明确允许登录和注销页面上的GET和POST->也破坏了登录.antMatcher
而是使用.antMatchers
,但是我想我将不能拥有两个不同的FormLogins 答案 0 :(得分: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")
。将不会收到在查询字符串中传递的任何参数。
因此,解决方案将始终使登录页面成为不受限制的资源。