Как можно обновить lastAccessedTime в Spring Session (Redis) при выполнении доступа через OAuth2?

Здравствуйте! 

У меня есть следующий вопрос: 

Я использую сервер oauth2 для реализации SSO (Single Sign-On), и у меня есть клиент (server-client), который проверяет валидность токена пользователя через запрос к (/oauth2/introspect) на сервере oauth2. Все авторизации связаны с сессией пользователя, и при истечении сессии удаляются все авторизации, что позволяет реализовать SLO (Single Log Out). Однако мне не совсем ясно, как обновить lastAccessedTime пользователя, когда клиент (server-client) отправляет запрос о том, что пользователь активно пользуется платформой. 

В сервере oauth2 я использую RedisIndexedSessionRepository, и у меня установлен таймаут сессии, после которого она истекает (spring.session.timeout: 5m). 

Как мне правильно продлить сессию пользователя при обращении через клиент-приложение к (/oauth2/introspect)? 

Буду признателен за любые комментарии. Спасибо!
  • 7 октября 2024 г. 16:55
Ответы на вопрос 1
Здравствуйте!

Обновление `lastAccessedTime` в Spring Session для пользователя, который использует ваш OAuth2 сервер, можно реализовать несколькими способами. Вот общий подход, который вы можете использовать:

1. **Использование `SessionRepository` для обновления сессии**: После того как вы провели проверку токена на `/oauth2/introspect`, вы можете получить текущую сессию пользователя и обновить её.

Примерный код может выглядеть так:

```java
@Autowired
private SessionRepository<ExpiringSession> sessionRepository; // или RedisIndexedSessionRepository

public void processIntrospection(String token) {
    // Ваш код для проверки токена
    boolean isValid = checkTokenValidity(token); // Псевдокод

    if (isValid) {
        // Получаем текущую сессию (например, по идентификатору пользователя или по токену)
        String sessionId = getSessionIdFromToken(token);
        
        Optional<ExpiringSession> sessionOptional = sessionRepository.findById(sessionId);
        if (sessionOptional.isPresent()) {
            ExpiringSession session = sessionOptional.get();
            // Обновляем lastAccessedTime
            session.setLastAccessedTime(Instant.now());
            sessionRepository.save(session); // Сохраняем обновленную сессию
        }
    }
}
```

2. **Автоматическое продление сессии**: Альтернативный подход может заключаться в интеграции механизма "keep-alive". Вы можете вызывать обновление сессии на стороне клиента в определенные интервалы времени (например, с помощью AJAX-запросов), когда пользователь взаимодействует с вашей платформой.

3. **Используйте фильтр или interceptor**: Вы также можете создать фильтр или interceptor, который будет автоматически обновлять сессию при каждом запросе к вашему приложению, проверяя при этом, валиден ли токен:

```java
@Component
public class SessionUpdateFilter extends OncePerRequestFilter {
    
    @Autowired
    private SessionRepository<ExpiringSession> sessionRepository;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String token = extractToken(request); // Метод, который получает токен из запроса
        if (token != null && isValidToken(token)) {
            String sessionId = getSessionIdFromToken(token);
            Optional<ExpiringSession> sessionOptional = sessionRepository.findById(sessionId);
            if (sessionOptional.isPresent()) {
                ExpiringSession session = sessionOptional.get();
                session.setLastAccessedTime(Instant.now());
                sessionRepository.save(session);
            }
        }
        filterChain.doFilter(request, response);
    }
}
```

Элемент, который нужно учитывать: как только вы обновляете `lastAccessedTime`, это изменяет время последнего доступа пользователя, и его сессия будет продлена до следующего истечения тайм-аута, установленного в вашем приложении.

Проверьте, что у вас есть правильно настроенные свойство `spring.session.timeout` и другие настройки сессий (например, `spring.session.redis.flush-mode`), чтобы это работало корректно.

Если вам нужна дополнительная информация, feel free to ask!
Похожие вопросы