В моем приложении есть несколько промежуточных и основных сервисов. Все сервисы являются Spring Boot и используют библиотеку Netflix. Когда пользователь запрашивает информацию, запрос будет / может передавать другие службы в цепочке, например:
Client <-> Zuul <-> Service B <-> Service A
Я настроил все службы (A и B) как ResourceServer, так что каждый доступ должен быть аутентифицирован. При запросе токена доступа (от Spring Security Server) и использовании его для запроса информации непосредственно из службы A все работает нормально. Когда я использую тот же токен для доступа к информации из службы B (которой требуется служба A в дальнейшем), я получаю ошибку «HTTP 401: требуется полная аутентификация». Служба B использует FeignClient для вызова службы A.
После некоторой отладки я обнаружил, что заголовок авторизации не передается из службы B в службу A. Служба B правильно проверяет сам токен, предоставляет доступ к методу и пытается выполнить запрос службы A.
Я попробовал RequestInterceptor, но безуспешно (ошибка «Scope 'request' не активна для текущего потока»)
@Component
public class OAuth2FeignRequestInterceptor implements RequestInterceptor {
private static final String AUTHORIZATION_HEADER = "Authorization";
private static final String BEARER_TOKEN_TYPE = "Bearer";
private final OAuth2ClientContext oauth2ClientContext;
public OAuth2FeignRequestInterceptor(OAuth2ClientContext oauth2ClientContext) {
Assert.notNull(oauth2ClientContext, "Context can not be null");
this.oauth2ClientContext = oauth2ClientContext;
}
@Override
public void apply(RequestTemplate template) {
if (template.headers().containsKey(AUTHORIZATION_HEADER)) {
...
} else if (oauth2ClientContext.getAccessTokenRequest().getExistingToken() == null) {
...
} else {
template.header(AUTHORIZATION_HEADER, String.format("%s %s", BEARER_TOKEN_TYPE,
oauth2ClientContext.getAccessTokenRequest().getExistingToken().toString()));
}
}
}
Это пример прокси-функции, использующей FeignClient:
@Autowired
private CategoryClient cat;
@HystrixCommand(fallbackMethod = "getAllFallback", commandProperties = {@HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "2") })
@GetMapping("/category")
public ResponseEntity<List<Category>> getAll() {
try {
ResponseEntity<List<Category>> categories = this.cat.getAll();
...
return categories;
} catch(Exception e) {
...
}
}
Есть ли какое-либо рабочее решение для передачи заголовка авторизации из прокси-функции в FeignClient, чтобы служба A получила заголовок и могла выполнять с ним собственную проверку аутентификации?




Нашел рабочее решение. Я до сих пор не знаю, является ли это «лучшим» способом сделать это, и если у кого-то есть лучшее решение, я буду рад, если вы поделитесь им. Но пока это работает так, как ожидалось:
@Bean
public RequestInterceptor requestTokenBearerInterceptor() {
return new RequestInterceptor() {
@Override
public void apply(RequestTemplate requestTemplate) {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails();
requestTemplate.header("Authorization", "Bearer " + details.getTokenValue());
}
};
}