从 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 = truehasRole = "User"时才被允许 在您的注销成功处理程序中,您正在使会话无效并重定向到 /user/login?logout 页面,但 /user/login 是受限制的资源,因此 FilterSecurityInterceptor 将重定向到配置的登录页面(.loginPage("/user/login")。因此您将不会收到任何传入查询的参数字符串。

因此解决方案将始终将登录页面设置为不受限制的资源。

【讨论】:

以上是关于从 CustomLogoutHandler 重定向到 'login?logout' 被重定向到 'login'的主要内容,如果未能解决你的问题,请参考以下文章

shell 重定向以及文件描述符

linux 从入门到跑路–重定向 管道

从动作过滤器属性重定向

vuejs - 如果已经登录,则从登录/注册重定向到主页,如果未登录 vue-router,则从其他页面重定向到登录

如何使用 ajax jQuery 重定向指定重定向 url

07输入输出重定向