Как использовать динамический планировщик в Spring Framework?

Я использую Spring Security 4.2. Я хочу заблокировать пользователя на 15 минут после 3 неудачных попыток входа. Чтобы заблокировать пользователя, измените пользователя status на BLOCK. Я хочу вернуть его ACTIVE через 15 минут.

Мне нужен планировщик динамических задач, который запускается через 15 минут и меняет пользователя status.

Важно! Я не хочу запускать метод каждые 15 минут, я хочу запускать метод через 15 минут, при необходимости.

Как мне это реализовать?


person Morteza Malvandi    schedule 05.07.2017    source источник


Ответы (2)


У меня есть подход. Я предполагаю, что вы должны использовать класс User следующим образом:

class User {
    // ...
    private Status status;
    private LocalDateTime lastUpdated;
    // ...
}

Таким образом, вы должны обновлять поля status и lastUpdated во время блокировки пользователя.

@Service
public class UserService {

    private UserRepository userRepository;

    @Transactional
    public void block(User user) {
        user.setStatus(Status.BLOCKED);
        user.setLastUpdated(LocalDateTime.now());
        userRepository.save(user);
    }
}

После этого вы можете использовать Spring Scheduler, который запускается каждую минуту и ​​находит пользователей, которые были заблокированы 15 минут назад, и устанавливает status в ACTIVE.

@Component
public class UserActivator {

    private boolean activateUsers = false;

    @Scheduled("0 * * * * *")
    public void activateUsers() {
        if (activateUsers) {
            // find users that were deactivated 15 minutes ago and change status to active
        }
    }
}

Не забудьте добавить @EnableScheduling в конфигурацию Spring.

person Mykola Yashchenko    schedule 05.07.2017
comment
У меня такая же проблема с блокировкой ip. Этот метод имеет слишком много накладных расходов. - person Morteza Malvandi; 05.07.2017
comment
хорошо, вы можете использовать собственный запрос для обновления статуса заблокированных пользователей. Так что не надо набирать пользователей раньше и будет эффективнее. - person Mykola Yashchenko; 05.07.2017
comment
также, если у вас есть проблема с блокировкой IP, вы можете создать отдельный метод. Spring позволяет настроить пул потоков для планировщиков, и вы можете сделать это без потери производительности. - person Mykola Yashchenko; 05.07.2017
comment
Я не хочу обновлять пользователя status каждые USER_STATUS_JOB раза, но я хочу обновлять его при необходимости. - person Morteza Malvandi; 06.07.2017
comment
Но вы будете обновлять только пользователей, которые были заблокированы 15 минут назад - person Mykola Yashchenko; 06.07.2017
comment
Да, я хочу вызвать метод, если это необходимо. Если нет заблокированных пользователей, метод не вызывается. - person Morteza Malvandi; 06.07.2017
comment
Я обновил свой ответ. Я добавил некоторый флаг, который показывает, есть ли пользователи, которых нужно активировать. Думаю в таком случае стоит подумать как обрабатывать этот флаг в случае многопоточности - person Mykola Yashchenko; 06.07.2017

У вас может быть определение таблицы для этого. Но я так обычно делаю.

Создайте отдельную таблицу для ведения счетчика отказов.

Затем на основе этого вы можете проверить уровень службы/контроллера.

    @Controller
    public Class LoginController{

        @Autowired
        private UserLoginFailureRepository userLoginFailureRepository;

        @Autowired
        private UserRepostory userRepository;

        @Transactional
        public void login(){

        UserLoginFailure loginFailure = userLoginFailureRepository.getUserLoginfailureDetails(username);
        if (loginFailure != null) {
        loginFailure.setFailureCount(1l + loginFailure.getFailureCount());

        if (loginFailure.getFailureCount() > loginFailureCount) {
        // block the user.
        User user = userRepository.getUser(username);
        user.setStatus(BLOCK);
        user.setModificationDate(LocalDateTime.now());
        }
    }
    }
    }

Создайте отдельное запланированное задание для проверки и обновления статуса пользователя и сброса счетчика UserLoginFailure.

    @Component
    public class userPasswordResetJob{

        @Autowired
        private UserLoginFailureRepository userLoginFailureRepository;

        @Autowired
        private UserRepostory userRepository;

        @Scheduled(cron = "${USER_STATUS_JOB}")
        public void loginDay() throws Exception{
            // Have your logic to update the User status and reset the failure count.

        }
    }
person Sangam Belose    schedule 05.07.2017
comment
Я не хочу обновлять пользователя status каждые USER_STATUS_JOB раза, но я хочу обновлять его при необходимости. - person Morteza Malvandi; 06.07.2017
comment
Просто проверьте, что modficationDate был за 15 минут до текущего времени, а затем только обновите его.. поэтому он не будет обновляться каждый раз, когда User_Status_Job. - person Sangam Belose; 06.07.2017
comment
Или другой вариант — создать событие sql DB, которое при необходимости выполнит обновление. - person Sangam Belose; 06.07.2017