Мой вопрос похож на
Как я могу ограничить количество попыток входа в Spring Security?
Проблема заключается в том, что после недавнего ответа с высоким рейтингом https://stackoverflow.com/a/35294221/1278112
Следующий код - мой подход.
@Component
public class AuthenticationEventListener {
@Autowired
private UserDetailsManager userDetailsManager;
private static final Logger LOGGER = LoggerFactory.getLogger(AuthenticationEventListener.class);
Set<RequestLimitRule> rules = Collections.singleton(RequestLimitRule.of(10, TimeUnit.MINUTES, 3)); // 3 request per 10 minute, per key
RequestRateLimiter limiter = new InMemorySlidingWindowRequestRateLimiter(rules);
@EventListener
public void authenticationSuccess(AuthenticationSuccessEvent event) {
String username = (String) event.getAuthentication().getName();
if (!limiter.overLimitWhenIncremented(username)) {
limiter.resetLimit(username);
}
}
@EventListener
public void authenticationFailed(AuthenticationFailureBadCredentialsEvent event) {
String username = (String) event.getAuthentication().getPrincipal();
boolean reachLimit = limiter.overLimitWhenIncremented(username);
if (reachLimit) {
User user = (User) userDetailsManager.loadUserByUsername(username);
//User is security.core.userdetails.User
user = (User) User.builder().username(user.getUsername()).accountExpired(!user.isAccountNonExpired())
.accountLocked(true).disabled(!user.isEnabled()).password(user.getPassword())
.authorities(user.getAuthorities()).build();
userDetailsManager.updateUser(user);
}
}
}
Было бы выброшено UserNameNotFoundException
вместо LockedException
, найдено InMemoryUserDetailsManager
по умолчанию @Autowired, при условии, что в нем нет информации о пользователе.
Поскольку информация о пользователях хранится в БД, JdbcUserDetailsManager
пытались заменить InMemoryUserDetailsManager
, но это позволило бы выполнить попытку входа в систему после сбоя через ограничитель.
После проверки исходного кода JdbcUserDetailsManager я обнаружил, что updateUser()
в нем не будет отслеживать свойство AccountNonLock
.
Ответ от @Ron Winch о Spring Security: выйти из системы, заблокировать или отключить пользователя по имени
Вам также нужно было знать, как заблокировать учетную запись. Spring Security
предоставляет механизм поддержки блокировки учетных записей.
Вы можете использовать реализацию UserDetailsManager для обновления
UserDetails возвращает false для isAccountNonLocked. Потом весна
Security DaoAuthenticationProvider будет использовать
preAuthenticationChecks гарантирует, что учетная запись не заблокирована.
Если вы написали свой собственный UserDetailsService, то встроенный
Реализации UserDetailsManager не будут работать, поэтому вам потребуется
обновите свою модель пользователя, чтобы пользовательский UserDetailsService создал
UserDetailsService, который возвращает false для isAccountNonLocked.
Таким образом, используется пользовательская реализация UserDetailsManager
для обновления UserDetails
. Это изменило бы запись БД. Но опять же он ничего не делает, когда отказывает через ограничитель.
После поиска ответ в
Spring Security: вместо BadCredentialsException выбрасывается LockedException, почему? указывают
DefaultPreAuthenticationChecks: проверить наличие заблокированных ...
После достижения ссылка безопасности пружины обнаружена DaoAuthenticationProvider
.
Нужно ли как-то настраивать, чтобы он работал с кастомом UserDetailsManager
?
Или есть другой лучший способ решить эту проблему?
Заранее спасибо.