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




Попробуйте отключить 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 Мне кажется, что идея использовать GET для выхода из системы - не самая лучшая идея, не так ли? Разве не было бы проще и лучше использовать POST-запрос, но с помощью JS, чтобы он выглядел как обычная ссылка?
Использование GET сопряжено с некоторыми рисками для безопасности. Но вы можете написать обычную форму, вам для этого не нужен JS.
@THEWaterfall прав, отключение csrf имеет некоторый риск безопасности, post безопаснее. Не реализуйте свой собственный контроллер, безопасность Spring дает вам все необходимые функции (даже по умолчанию).
Мне удалось протестировать несколько способов, и вот что у меня есть:
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
http.csrf().disable()
.deleteCookies("remember-me", "JSESSIONID").invalidateHttpSession(true).clearAuthentication(true).logoutSuccessUrl("/")
(Я не уверен, но мне кажется, что это не работает, потому что вы выполняете запрос GET и используете свой контроллер для управления выходом из системы)
Сначала вы добавляете имя для файла 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)
Решения для этого вы можете найти на Эта тема.
Обобщая все вышесказанное, могу сказать, что если вам нужен контроллер, вы должны программно все написать сами (кто-то скажет, что это изобретение колеса заново).
Тем не менее, можно использовать запрос GET, но без контроллера, который описан в 1-й и 2-й позициях списка.
(Последствия использования запроса GET записаны в Документация CSRF, и он не рекомендует использовать запрос GET из-за его неуязвимости.)
Поэтому последнее, что я решил сделать своим любимым, - это сделать запрос POST похожим на запрос GET (использовать его как ссылку) с помощью JS или HTML и CSS. И поскольку вы используете запрос POST, у вас есть защита от CSRF.
Надеюсь, это кому-то поможет.
Можете ли вы поделиться своей конфигурацией безопасности?