Передача токенов между микросервисами с помощью веб-клиента - PullRequest
0 голосов
/ 07 мая 2020

У меня есть два микросервиса, назовем их A и B, за Spring Cloud Gateway. Также есть OAuthServer. Когда пользователи отправляют запрос в службу A, они должны сначала получить токен JWT от oAuthServer с помощью потока паролей.

Предостережение заключается в том, что службе A необходимо взаимодействовать со службой B, но для этого ей нужен доступ токен. Идея состоит в том, чтобы использовать JWT, предоставляемый пользователем, при доступе к службе A, ретранслируя его службе B, таким образом выполняя запрос.

В предыдущих версиях Spring Boot я бы использовал OAuth2RestTemplate, но теперь мне нужно использовать Webclient.

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

@Component
public class JWTAuthorizationFilter extends OncePerRequestFilter {

private static final Logger log = LoggerFactory.getLogger(JWTAuthorizationFilter.class);

private final String HEADER = "Authorization";
private final String PREFIX = "Bearer ";

private TokenStore tokenStore;

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
        throws ServletException, IOException {

    if (checkJWTToken(request, response)) {
        String token = extractToken(request);
        if (token != null) {
            log.info("*****RECEIVED REQUEST WITH TOKEN {}. ", token);
            log.info("***** Will store it for future requests.");
            tokenStore = TokenStore.getInstance();
            tokenStore.setToken(token);
            // setUpSpringAuthentication(token);
        } else {
            SecurityContextHolder.clearContext();
        }
    }
    chain.doFilter(request, response);

}

private String extractToken(HttpServletRequest request) {
    String jwtToken = request.getHeader(HEADER).replace(PREFIX, "");
    return jwtToken;
}

private boolean checkJWTToken(HttpServletRequest request, HttpServletResponse res) {
    String authenticationHeader = request.getHeader(HEADER);
    if (authenticationHeader == null || !authenticationHeader.startsWith(PREFIX))
        return false;
    return true;
}

TokenStore

public class TokenStore {

private static TokenStore instance;

private String token;

private TokenStore() {
}

public static synchronized TokenStore getInstance() {
    if (instance == null) {
        instance = new TokenStore();
    }
    return instance;
}

public String getToken() {
    return token;
}

public synchronized void setToken(String token) {
    this.token = token;
}

}

И, наконец, веб-клиент:

@Bean
@LoadBalanced
@Profile("!default")
public WebClient.Builder loadBalancedWebClientBuilder() {
    final WebClient.Builder builder = WebClient.builder();
    return builder;
}

Использование:

Mono<Map<Long, DrawDTO>> mono = getWebClient().get().uri(url)
            .header("Authorization", "Bearer " + tokenStore.getToken()).retrieve().bodyToFlux(DTO.class)
            .map(d -> Tuples.of(Long.parseLong(d.getUniqueId()), d))
            .collectMap(tuple -> tuple.getT1(), tuple -> tuple.getT2()).log()
            .onErrorMap(WebClientResponseException.class, ex -> handleException(ex)).timeout(Duration.ofSeconds(5));

Однако , Я почти уверен, что это ошибка. TokenStore является одноэлементным, если два запроса приходят от пользователей X и Y , при этом второй вызов фильтра переопределит токен первого. Таким образом, служба A будет использовать токен пользователя Y для выполнения запроса пользователя X . Таким образом, если уровень доступа пользователя X ниже, чем Y , это проблема безопасности.

Я ошибаюсь насчет вышеизложенного? Если да, что я могу сделать, чтобы это исправить?

Я нашел одно решение - использовать учетные данные клиента для внутрисервисной связи, но я не уверен на 100%, как это сделать с помощью Spring Boot 2.2.6 и Spring Security 5.

Есть ли правильный способ сделать то, что я задумал изначально?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...