Блокировка учетных записей через EventListener основывается на записи пользователя в базе - PullRequest
0 голосов
/ 31 августа 2018

Мой вопрос похож на Как я могу ограничить количество попыток входа в 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?
Или есть другой лучший способ решить эту проблему?
Заранее спасибо.

1 Ответ

0 голосов
/ 01 сентября 2018

@ Рон Винч совершенно прав

Вы можете использовать реализацию UserDetailsManager для обновления UserDetails возвращает false для isAccountNonLocked. Потом весна Security DaoAuthenticationProvider будет использовать preAuthenticationChecks гарантирует, что учетная запись не заблокирована.

Однако InMemoryUserDetailsManager и JdbcUserDetailsManager мне не подходят.

Так что я реализую UserDetailsService вместо UserDetailsManager

Если вы написали свой собственный UserDetailsService, то встроенный Реализации UserDetailsManager не будут работать, поэтому вам потребуется обновите свою модель пользователя, чтобы пользовательский UserDetailsService создал UserDetailsService, который возвращает false для isAccountNonLocked.

И введите его в AuthenticationManager через AuthenticationManagerBuilder

public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;

@Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(userDetailsService).passwordEncoder(NoOpPasswordEncoder.getInstance());

    ....
}

связанная часть UserDetailsServiceImpl.java

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    ....

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //the custom implemetation
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...