Как отключить функцию "Запомнить меня" при выходе из системы?

Ну, я не реализую PersistentTokenBasedRememberMeServices, поэтому не могу использовать .logout(request, response, auth). Но я использую JdbcTokenRepositoryImpl, чтобы использовать PersistentTokenRepository для функции «запомнить меня».

LogoutController:

@Controller
public class LogoutController {

    @RequestMapping(value = {"/logout"}, method = RequestMethod.GET)
    public String logout() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();

        if (auth != null) {
            SecurityContextHolder.getContext().setAuthentication(null);
        }

        return "redirect:/login?logout";
    }
}

Конфигурация безопасности:

@Configuration
@EnableWebSecurity
public class AppSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private DataSource dataSource;

    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authProvider());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
            .antMatchers("/", "/playground").hasAnyRole("ROOT", "MODER", "USER")
            .antMatchers("/users/**").hasAnyRole("ROOT", "MODER")
        .and()
            .formLogin().loginPage("/login").loginProcessingUrl("/login").failureHandler(customAuthenticationFailureHandler())
        .and()
            .rememberMe().rememberMeParameter("remember-me").tokenRepository(persistentTokenRepository()).userDetailsService(userDetailsService)
        .and()
            .logout().logoutUrl("/logout");
    }

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public DaoAuthenticationProvider authProvider() {
        DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
        authProvider.setPasswordEncoder(passwordEncoder());
        authProvider.setUserDetailsService(userDetailsService);
        return authProvider;
    }

    @Bean
    public AuthenticationFailureHandler customAuthenticationFailureHandler() {
        return new CustomAuthenticationFailureHandler();
    }

    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl jdbcTokenRepository = new JdbcTokenRepositoryImpl();
        jdbcTokenRepository.setDataSource(dataSource);
        return jdbcTokenRepository;
    }

Когда я вхожу в систему с помощью «запомни меня», я не могу выйти из системы. Думаю, из-за функции «запомни меня». Что я должен добавить в LogoutController, чтобы обеспечить правильный выход из системы?

Примечание: дело в том, что если я просто использую метод POST при выходе из системы, он отлично работает, но я бы хотел использовать метод GET, и поэтому мне нужно создать контроллер выхода для выполнения метода get.

Можете ли вы поделиться своей конфигурацией безопасности?

chaoluo 09.01.2019 10:03

Не используйте контроллер. Настройте Spring Security, чтобы разрешить выход с помощью запроса GET. См. stackoverflow.com/questions/20333176/…, чтобы узнать, как это сделать.

M. Deinum 09.01.2019 11:20
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
2
615
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Попробуйте отключить crsf (http.csrf().disable()).

Реализация по умолчанию в весеннем фильтре выхода из системы безопасности:

        if (http.getConfigurer(CsrfConfigurer.class) != null) {
            this.logoutRequestMatcher = new AntPathRequestMatcher(this.logoutUrl, "POST");
        }
        else {
            this.logoutRequestMatcher = new OrRequestMatcher(
                new AntPathRequestMatcher(this.logoutUrl, "GET"),
                new AntPathRequestMatcher(this.logoutUrl, "POST"),
                new AntPathRequestMatcher(this.logoutUrl, "PUT"),
                new AntPathRequestMatcher(this.logoutUrl, "DELETE")
            );
        }

как вы можете видеть, включен ли ваш Csrf (по умолчанию он включен, даже если вы переопределяете protected void configure(HttpSecurity http)), тогда будет работать только метод POST, если не все работают.

BTW: Вы уверены, что ваш запрос достигает LogoutController, потому что я думаю, что он использует стандартный весенний механизм выхода из системы безопасности? (Чтобы отключить его, сделайте http.logout().disable(), так же, как csrf, он включен по умолчанию)

Предлагать сделать все приложение менее безопасным, чтобы получить функцию выхода из системы, работающую с GET, на самом деле неразумный поступок.

M. Deinum 09.01.2019 14:54

@ M.Deinum Мне кажется, что идея использовать GET для выхода из системы - не самая лучшая идея, не так ли? Разве не было бы проще и лучше использовать POST-запрос, но с помощью JS, чтобы он выглядел как обычная ссылка?

THE Waterfall 09.01.2019 15:03

Использование GET сопряжено с некоторыми рисками для безопасности. Но вы можете написать обычную форму, вам для этого не нужен JS.

M. Deinum 09.01.2019 15:09

@THEWaterfall прав, отключение csrf имеет некоторый риск безопасности, post безопаснее. Не реализуйте свой собственный контроллер, безопасность Spring дает вам все необходимые функции (даже по умолчанию).

Andrew Sasha 10.01.2019 10:18
Ответ принят как подходящий

Подвести итог.

Мне удалось протестировать несколько способов, и вот что у меня есть:

  1. Как предположил М. Дейнум в комментариях, можно не использовать контроллер и, тем не менее, выйти из системы с помощью запроса GET. Вот.

.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))

  1. Как предложил Эндрю Саша в разделе ответов, вы можете отключить csrf, поскольку он намеренно предотвращает использование запроса GET. И теперь вы можете использовать запрос GET для выхода из системы даже без использования какого-либо контроллера.

http.csrf().disable()

  1. Если вы все еще хотите использовать контроллер, вам поможет никто из следующих вещей

.deleteCookies("remember-me", "JSESSIONID")
.invalidateHttpSession(true)
.clearAuthentication(true)
.logoutSuccessUrl("/")

(Я не уверен, но мне кажется, что это не работает, потому что вы выполняете запрос GET и используете свой контроллер для управления выходом из системы)

  1. Итак, вы можете сделать это программно

Сначала вы добавляете имя для файла cookie «запомнить меня» в конфигурации безопасности Spring:

rememberMe().rememberMeCookieName("remember-me")

А затем в контроллере выхода из системы добавьте это:

String cookieName = "remember-me";
Cookie cookie = new Cookie(cookieName, null);
cookie.setMaxAge(0);
cookie.setPath(StringUtils.hasLength(request.getContextPath()) ? request.getContextPath() : "/");
response.addCookie(cookie);

Единственная проблема здесь в том, что вам нужно вручную удалить запись из таблицы persistent_logins.

(Чтобы получить запрос и ответ, вы просто передаете их в метод public void logout(HttpServletRequest request, HttpServletResponse response)

  1. Можно использовать запрос POST, но использовать его как ссылку с помощью JavaScript или даже простого HTML и CSS.

Решения для этого вы можете найти на Эта тема.

Так что у нас здесь?

Обобщая все вышесказанное, могу сказать, что если вам нужен контроллер, вы должны программно все написать сами (кто-то скажет, что это изобретение колеса заново).

Тем не менее, можно использовать запрос GET, но без контроллера, который описан в 1-й и 2-й позициях списка.

(Последствия использования запроса GET записаны в Документация CSRF, и он не рекомендует использовать запрос GET из-за его неуязвимости.)

Поэтому последнее, что я решил сделать своим любимым, - это сделать запрос POST похожим на запрос GET (использовать его как ссылку) с помощью JS или HTML и CSS. И поскольку вы используете запрос POST, у вас есть защита от CSRF.

Надеюсь, это кому-то поможет.

Другие вопросы по теме