Я пытаюсь аутентифицировать пользователя (это работает) и получить токен пользователя из контекста, и это не работает.
У меня есть простое микросервисное приложение в качестве моего домашнего проекта, и я использую WebFlux в качестве веб-фреймворка.Я попытался отладить ReactiveSecurityContextHolder # getContext и внутри flatMap Я вижу мой маркер пользователя внутри контекста, но в моем приложении у меня есть пустой контекст.
SecurityConfiguration.java
@EnableWebFluxSecurity
public class SecurityConfiguration {
@Bean
public SecurityWebFilterChain securityWebFilterChain(
AuthenticationWebFilter authenticationWebFilter,
ServerHttpSecurity http) {
return http
.csrf().disable()
.httpBasic().disable()
.formLogin().disable()
.logout().disable()
.addFilterAt(authenticationWebFilter, SecurityWebFiltersOrder.AUTHENTICATION)
.authorizeExchange()
.anyExchange().authenticated()
.and()
.build();
}
@Bean
public AuthenticationWebFilter authenticationWebFilter(
SecurityTokenBasedAuthenticationManager authenticationManager,
TokenAuthenticationConverter tokenAuthenticationConverter) {
AuthenticationWebFilter authenticationWebFilter = new AuthenticationWebFilter(authenticationManager);
authenticationWebFilter.setServerAuthenticationConverter(tokenAuthenticationConverter);
authenticationWebFilter.setSecurityContextRepository(new WebSessionServerSecurityContextRepository());
return authenticationWebFilter;
}
}
ReactiveAuthenticationManager.java
@Slf4j
@Component
@AllArgsConstructor
public class SecurityTokenBasedAuthenticationManager implements ReactiveAuthenticationManager {
private final AuthWebClient authWebClient;
@Override
public Mono<Authentication> authenticate(Authentication authentication) {
return Mono.just(authentication)
.switchIfEmpty(Mono.defer(this::raiseBadCredentials))
.cast(Authorization.class)
.flatMap(this::authenticateToken)
.map(user ->
new Authorization(user, (AuthHeaders) authentication.getCredentials()));
}
private <T> Mono<T> raiseBadCredentials() {
return Mono.error(new TokenValidationException("Invalid Credentials"));
}
private Mono<User> authenticateToken(Authorization authenticationToken) {
AuthHeaders authHeaders = (AuthHeaders) authenticationToken.getCredentials();
return Optional.of(authHeaders)
.map(headers -> authWebClient.validateUserToken(authHeaders.getAuthToken(), authHeaders.getRequestId())
.doOnSuccess(user -> log
.info("Authenticated user " + user.getUsername() + ", setting security context")))
.orElseThrow(() -> new MissingHeaderException("Authorization is missing"));
}
}
SecurityUtils.java
@Slf4j
public class SecurityUtils {
public static Mono<AuthHeaders> getAuthHeaders() {
return getSecurityContext()
.map(SecurityContext::getAuthentication)
.map(Authentication::getCredentials)
.cast(AuthHeaders.class)
.doOnSuccess(authHeaders -> log.info("Auth headers: {}", authHeaders));
}
private static Mono<SecurityContext> getSecurityContext() {
return ReactiveSecurityContextHolder.getContext();
}
}
Здание WebClient
(...)
WebClient.builder()
.baseUrl(url)
.filter(loggingFilter)
.defaultHeaders(httpHeaders ->
getAuthHeaders()
.doOnNext(headers -> httpHeaders.putAll(
Map.of(
REQUEST_ID, singletonList(headers.getRequestId()),
AUTHORIZATION, singletonList(headers.getAuthToken())))))
.build()
(...)
Основная проблема заключается всоздание моего WebClient - я ожидаю, что у меня будет полный webclient с запрошенным заголовком, но, как я описал выше - у меня есть пустой контекст внутри SecurityUtils.java