Как получить токен JWT в архитектуре BFF Spring Webflux

Я реализовал архитектуру Backend for Frontend (BFF) с помощью Spring Webflux, используя фильтр TokenRelay. Мой интерфейс взаимодействует с BFF с помощью файла cookie в качестве механизма аутентификации, а BFF получает токен JWT от Cognito (или сохраняется в сеансе Spring, не уверен. Для меня это волшебство) и отправляет его в заголовке на серверы ресурсов. Здесь узел BFF работает как конфиденциальный клиент oauth2, и браузеру не нужно хранить какой-либо токен JWT или что-то подобное.

Это делается прозрачно для меня как разработчика. Он настроен правильно и работает без проблем. Если я делаю запрос к https://bff-url/api/users/{user-id} из внешнего интерфейса, он работает, автоматически перенаправляясь на микросервис пользователей и прикрепляя токен в заголовок.

Однако давайте рассмотрим конечную точку, которой нет ни на одном ресурсном сервере (микросервисе). Эта конечная точка находится в BFF.

Этот URL-адрес конечной точки — https://bff-url/api/auth/me. Я определил следующим образом:

@RestController
@RequestMapping("/api/auth")
public class CurrentUserController {

public CurrentUserController() {
}

@GetMapping("/me")
@ResponseBody
public Mono<UserResponseDTO> getCurrentUser(Authentication authentication) {
    String userId = ((DefaultOidcUser)authentication.getPrincipal()).getClaim("custom:userId");
    // TODO call to users service users with this userId
    return Mono.empty();
  }
}

Я просто хочу получить идентификатор из сеанса (я его получаю) и вызвать службу пользователей, как обычно. Я не знаю, какой подход лучше всего сделать:

  • Каким-то образом получить токен и внедрить WebClient для совершения вызова. Проблема в том, что мне не удалось получить этот токен из файла cookie. У меня есть сеанс Redis, который содержит идентификатор токена с некоторой информацией об открытом идентификаторе, но не сам токен JWT.
  • Попробуйте использовать какую-нибудь конфигурацию Spring, которая вводит в WebClient то же поведение, что и платформа при автоматическом применении ретрансляции токенов. Мне тоже не удалось этого получить, введенные мной веб-клиенты не отправляли волшебным образом токен доступа.

Я открыт для любого другого подхода в соответствии с рекомендациями Spring, поскольку я не эксперт Spring и, вероятно, что-то упускаю.

0
0
74
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

Как получить токен JWT в BFF

Самый простой способ — использовать фильтр TokenRelay, чтобы Spring Cloud Gateway прикрепил его в качестве заголовка авторизации носителя к нижестоящему серверу ресурсов.

BFF получает токен JWT от Cognito (или сохраняется в сеансе Spring, не уверен. Для меня это волшебство)

И то, и другое: BFF — это клиент OAuth2, настроенный на использование потока кода авторизации (oauth2Login в формулировке Spring Security) => именно так он изначально получает токены с сервера авторизации (дальнейшие токены могут быть получены с использованием потока токена обновления). Затем он сохраняет эти токены в сеансах. Таким образом, для дальнейших запросов к BFF токены считываются в сеансе (если только срок его действия не истек или наступит в течение следующей минуты).

Я открыт для любого другого подхода в соответствии с рекомендациями Spring, поскольку я не эксперт Spring и, вероятно, что-то упускаю.

Самый простой способ — использовать BFF исключительно для целей маршрутизации (адаптация файлов cookie сеанса / авторизации носителя на лету) и разместить его /me на нижестоящем сервере ресурсов. Поскольку TokenRelay прикрепляет токен доступа для текущего пользователя, все, что необходимо на нижестоящем сервере ресурсов, — это отразить утверждения токена доступа (все это или, возможно, лучше, только необходимые). Это то, что я делаю в этой статье Baeldung, посвященной шаблону OAuth2 BFF , в другом проекте и вообще во многих других местах.

Если вы предпочитаете использовать конечную точку /me на BFF, есть два варианта (но ни один из них не является таким простым и масштабируемым, как приведенный выше):

  • создайте UserDto только из утверждений токена идентификатора (большинство серверов авторизации позволяют обогащать токены идентификатора, если по умолчанию он не содержит всех необходимых вам утверждений).
  • получить токен доступа из ReactiveOAuth2AuthorizedClientManager для авторизации запроса к пользовательскому сервису, а затем проанализировать ответ для создания UserDto (но тогда почему бы не использовать шлюзовой маршрут к пользовательскому сервису с фильтром TokenRelay?)

Огромное спасибо @ch4mp за этот очень подробный ответ. Ты ведешь меня к успеху! В конце концов я решил получить токен доступа от AuthorizedClientManager, так как хочу отделить его от службы пользователей. Фактически, мне не нужен токен, поскольку Spring сделал ретрансляцию токена прозрачной при настройке oauth2Client в компоненте WebClient. Спасибо!

Juan Aguilar Guisado 11.07.2024 16:54

Я думаю, что будет чище держать бизнес-логику подальше от шлюза. Единственное исключение, которое я делаю, — это доступные параметры входа в систему, поскольку в BFF определяются конфигурации OAuth2 provider(s) и registration(s). Эта конечная точка информации о владельце ресурса лучше подходит для нижестоящего сервера ресурсов, к которому, естественно, уже прикреплен токен доступа. Мои «пользовательские сервисы» обычно представляют собой адаптер к API сервера авторизации, и мне кажется удобным поместить на него конечную точку, отражающую владельца ресурса, но вы можете прекрасно создать выделенные микросервисы, если считаете, что это чище.

ch4mp 11.07.2024 19:57

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