Перенаправление с CustomLogoutHandler на «login? Logout» перенаправляется на «login» - PullRequest
2 голосов
/ 11 октября 2019

У меня есть две защищенные области, для которых я предоставляю логины на основе форм.

  • /user
  • /admin

Следующие работыкак и ожидалось:

  • Перенаправление на страницу входа при доступе к защищенному ресурсу
  • Перенаправление на страницу входа с параметром ?error, когда учетные данные были ложными
  • Запрет доступак защищенному ресурсу на основе определенных ролей

Не работает следующее:

  • Перенаправление на страницу входа после выхода из системы

При входе в системуout, я перенаправляю на /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 приводит к 302, а затем делается новый запрос для user/login. Это происходит, когда я вручную редактирую URL-адрес в строке URL-адреса браузера или когда запускаю выход через приложение FORM-Post из приложения.

Когда я удаляю logoutSuccessHandler, я могу оба, ввести URL-адрес в браузере вручнуюи вызвать его из моего приложения FORM-Post в приложении.

Я также попытался:

  • переместить URL-адреса для входа и выхода из системы из пути /user -> который сломал Логин
  • , определяя третью конфигурацию с Order(1), явно разрешающим GET и POST на страницах входа и выхода из системы -> который также сломал Логин
  • не использует .antMatcher и использовать .antMatchers вместо этого, однако тогда я думаю, что не смогу иметь два разных FormLogins

1 Ответ

1 голос
/ 12 октября 2019

Я знаю, что этот тип проблем ставит большой вопросительный знак и заставляет чесать голову, думая ПОЧЕМУ ?

Решение будет.

@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"). Следовательно, вы не получите никаких параметров, переданных в строке запроса.

Следовательно, решением всегда будет создание страницы входа в качестве неограниченного ресурса.

...