Дополнительная логика проверки при обновлении токена доступа

Я работаю над реализацией токенов доступа и обновления с помощью OAuth 2.0. Я реализовал собственный тип гранта и могу обновить токен доступа, используя токен обновления с уже существующими OAuth2RefreshTokenAuthenticationConverter и OAuth2RefreshTokenAuthenticationProvider. Проблема в том, что перед предоставлением нового токена доступа мне нужно вызвать в базу данных, чтобы убедиться, что пользователь все еще активен, и выполнить дополнительные проверки (например, чтобы определить, потеряли ли они за это время право на вход в систему). В идеале мне нужно вызвать аутентификациюManager.authenticate перед предоставлением нового токена доступа.

Я попытался реализовать фильтр OncePerRequest для дополнительной проверки, но внутри него у меня нет доступа к имени пользователя, только к токену обновления, типу гранта и области действия.

Существует ли фильтр, который принимает OAuth2AuthenticationToken и запускается непосредственно перед OAuth2RefreshTokenAuthenticationProvider?

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

Заранее спасибо!

Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
0
79
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Напишите собственный AuthenticationProvider для выполнения дополнительных проверок. Он запустится до запуска OAuth2RefreshTokenAuthenticationProvider. Например:

/**
 * If the user account is locked, then throws an exception, which stops subsequent
 * {@link AuthenticationProvider#authenticate AuthenticationProvider}s being tried.
 */
@RequiredArgsConstructor
public class UserDetailsRefreshTokenAuthenticationProvider implements AuthenticationProvider {

  private final CustomUserDetailsService userDetailsService;

  @Override
  public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    var authenticationToken = (OAuth2RefreshTokenAuthenticationToken) authentication;
    String refreshToken = authenticationToken.getRefreshToken();
    if (userDetailsService.isAccountLocked(refreshToken)) {
      throw new LockedException("User account is locked");
    }

    return null;
  }

  @Override
  public boolean supports(Class<?> authentication) {
    return OAuth2RefreshTokenAuthenticationToken.class.isAssignableFrom(authentication);
  }
}

Добавьте этот пользовательский AuthenticationProvider в конечную точку токена:

@Bean
public SecurityFilterChain authorizationServerSecurityFilterChain(
    HttpSecurity http,
    UserDetailsRefreshTokenAuthenticationProvider userDetailsRefreshTokenAuthenticationProvider
) throws Exception {
  OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);

  http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
      .tokenEndpoint(endpoint -> endpoint              
          .authenticationProvider(userDetailsRefreshTokenAuthenticationProvider)

  // ...

Спасибо за Ваш ответ! В реализации я видел, что «.authenticationProvider()» ставит указанного поставщика аутентификации первым элементом в списке поставщиков аутентификации, и это будет работать. Тем временем я реализовал RefreshTokenValidationFilter, который расширяет OncePerRequestFilter, и реализовал там свою логику. По вашему мнению, какой подход лучше: использовать фильтр или поставщика аутентификации?

Filip 06.07.2024 13:33

Ваш RefreshTokenValidationFilter также отвечает за чтение параметров HTTP-запроса и запись HTTP-ответа? Об этом позаботится OAuth2TokenEndpointFilter Spring Authorization Server, поэтому вам нужно всего лишь реализовать собственный поставщик аутентификации.

Chin Huang 08.07.2024 22:19

Он не записывает ответ, но если requestURI имеет значение oauth/token и содержит тип грантаrefresh_token, он вызывает диспетчер аутентификации с помощью PreAuthenticatedAuthenticationToken, и если все в порядке, то он вызывает следующий фильтр в цепочке с помощью 'filterChain.doFilter(request , ответ)', в противном случае выдается ошибка. Это правильный способ сделать это?

Filip 10.07.2024 13:01

На самом деле я напрямую использую PreAuthenticatedAuthenticationProvider.authenticate вместо AuthenticationManager.

Filip 10.07.2024 15:45

Если запрос токена не удался, то спецификация OAuth 2.0 требует, чтобы сервер авторизации возвращал ответ об ошибке. Если ваш фильтр выдает исключение, что отправляет ответ об ошибке?

Chin Huang 10.07.2024 16:56

Извините за задержку, как-то пропустил ваш ответ. RefreshTokenValidationFilter добавляется перед UsernamePasswordAuthenticationFilter, и когда он генерирует исключение, исключение обрабатывается и записывается в ответ методом OAuth2ClientAuthenticationFilter.onAuthenticationFailure(Ht‌​tpServletRequest request, HttpServletResponse response, AuthenticationExceptionException). В ответе этот метод показывает только код ошибки и скрывает описание ошибки.

Filip 15.07.2024 21:41

Кстати, если я реализую RefreshTokenAuthenticationProvider, мне всегда придется выдавать один из типов «AccountStatusException», чтобы предотвратить обновление токена доступа AuthenticationProvider по умолчанию, или есть другой способ? Когда я вызываю исключение OAuth2AuthException, токен доступа по-прежнему обновляется с помощью RefreshTokenAuhenticationProvider по умолчанию, если токен обновления действителен.

Filip 15.07.2024 22:29

В Javadoc говорится, что вы должны выдать исключение AccountStatusException, чтобы предотвратить выполнение последующих поставщиков в списке.

Chin Huang 16.07.2024 01:48

Огромное спасибо, Чин, за все ответы. Я реализовал это так, как вы предложили.

Filip 17.07.2024 18:00

Другие вопросы по теме

Какова связь между временем простоя сеанса единого входа Keycloak и временем ожидания сеанса Spring?
Как обойти страницу входа в систему keycloak и предоставить предложенному клиентом идентификатору Spring Security
JWTEncoder: не удалось выбрать ключ подписи JWK
Spring OAuth2 Resource Server – лучший способ преобразовать Jwt/JwtAuthenticationToken в другую аутентификацию
Токен обновления не используется Spring OAuth2 по истечении срока действия токена доступа
Как отключить Spring (Boot) Security OAuth на основе профиля конфигурации или определенного свойства?
Код авторизации без использования формы входа
Безопасность OAuth2 Spring с представлением нескольких API как нескольких серверов ресурсов
Настройка токена OAuth2 с помощью сервера авторизации Spring OAuth2 1.1.0 (Spring Boot 3.1.0)
Является ли spring-authorization-server подходящим инструментом для подключения к существующему серверу OIDC, предоставленному предприятием?

Похожие вопросы

Обработка внутренней ошибки сервера, когда эмитент OAuth недоступен в WebFluxSecurity
Почему защита CSRF необходима для подключения к веб-сокетам, если Spring Security реализует политику одинакового происхождения на уровне сервера?
Spring Security + Keycloak (с самоподписанными сертификатами) – как отключить проверку имени хоста?
Ошибка конфигурации безопасности при обновлении версии приложения весенней загрузки с 2.x.x до 3.3.0
Доступ запрещен даже при использовании AnonymousAuthenticationFilter
Spring безопасность 6 - авторизация не работает
Spring Boot 2.5.6 без Spring Security и конфигурации безопасности, обновленной до Spring Boot 3, из-за чего swagger не работает
Какова связь между временем простоя сеанса единого входа Keycloak и временем ожидания сеанса Spring?
Почему нам нужно загружать данные пользователя из БД для каждого запроса при аутентификации JWT с помощью Spring Security?
Перенос org.springframework.security.jwt.Jwt