Я пытаюсь настроить Spring Security в реактивном приложении Spring Boot с внешним интерфейсом Vuejs, который перенаправляет пользователей к внешнему провайдеру OpenID (для проверки подлинности) в случае неаутентификации.После проверки подлинности пользователей с помощью поставщика OpenID и перенаправления обратно в приложение (веб-интерфейс) будет создан UsernamePasswordAuthenticationToken (Authentication) на основе ответа поставщика OpenID, который будет проверен вручную.
Однако при этом приложение, похоже, не может обнаружить, что пользователь прошел проверку подлинности, поскольку AuthenticationEntryPoint все еще вызывается со следующим исключением, а preAuthenticationFilter (показанный ниже) по-прежнему вызывается повторно из-забудучи аутентифицированным.
org.springframework.security.authentication.AuthenticationCredentialsNotFoundException: Not Authenticated
at org.springframework.security.web.server.authorization.ExceptionTranslationWebFilter.commenceAuthentication(ExceptionTranslationWebFilter.java:72)
at org.springframework.security.web.server.authorization.ExceptionTranslationWebFilter.lambda$filter$1(ExceptionTranslationWebFilter.java:44)
at reactor.core.publisher.Mono.lambda$onErrorResume$25(Mono.java:3146)
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onError(FluxOnErrorResume.java:88)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onError(Operators.java:1748)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onError(MonoFlatMap.java:165)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onError(Operators.java:1748)
at reactor.core.publisher.Operators.error(Operators.java:181)
at reactor.core.publisher.MonoError.subscribe(MonoError.java:52)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
at reactor.core.publisher.Mono.subscribe(Mono.java:3852)
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onComplete(FluxSwitchIfEmpty.java:75)
at reactor.core.publisher.FluxFilter$FilterSubscriber.onComplete(FluxFilter.java:160)
at reactor.core.publisher.FluxDefaultIfEmpty$DefaultIfEmptySubscriber.onComplete(FluxDefaultIfEmpty.java:98)
at reactor.core.publisher.MonoNext$NextSubscriber.onComplete(MonoNext.java:96)
at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:77)
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.innerNext(FluxConcatMap.java:275)
at reactor.core.publisher.FluxConcatMap$ConcatMapInner.onNext(FluxConcatMap.java:849)
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1515)
at reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:241)
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1515)
at reactor.core.publisher.FluxDefaultIfEmpty$DefaultIfEmptySubscriber.onComplete(FluxDefaultIfEmpty.java:100)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onComplete(FluxMapFuseable.java:144)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onComplete(FluxMapFuseable.java:144)
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onComplete(FluxFilterFuseable.java:166)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.secondComplete(MonoFlatMap.java:189)
at reactor.core.publisher.MonoFlatMap$FlatMapInner.onComplete(MonoFlatMap.java:260)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:141)
at reactor.core.publisher.FluxMap$MapSubscriber.onNext(FluxMap.java:114)
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1515)
at reactor.core.publisher.MonoProcessor.subscribe(MonoProcessor.java:457)
at reactor.core.publisher.MonoMap.subscribe(MonoMap.java:55)
at reactor.core.publisher.MonoFlatMap.subscribe(MonoFlatMap.java:60)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:150)
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onNext(FluxFilterFuseable.java:113)
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2071)
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.request(FluxFilterFuseable.java:185)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:103)
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onSubscribe(FluxFilterFuseable.java:82)
at reactor.core.publisher.MonoCurrentContext.subscribe(MonoCurrentContext.java:35)
at reactor.core.publisher.MonoFilterFuseable.subscribe(MonoFilterFuseable.java:47)
at reactor.core.publisher.MonoFlatMap.subscribe(MonoFlatMap.java:60)
at reactor.core.publisher.MonoFilterFuseable.subscribe(MonoFilterFuseable.java:47)
at reactor.core.publisher.MonoMapFuseable.subscribe(MonoMapFuseable.java:59)
at reactor.core.publisher.MonoMapFuseable.subscribe(MonoMapFuseable.java:59)
at reactor.core.publisher.MonoDefaultIfEmpty.subscribe(MonoDefaultIfEmpty.java:37)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:150)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:121)
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onNext(FluxFilterFuseable.java:113)
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2071)
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.request(FluxFilterFuseable.java:185)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.request(FluxMapFuseable.java:162)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:103)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onSubscribe(FluxMapFuseable.java:90)
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onSubscribe(FluxFilterFuseable.java:82)
at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:54)
at reactor.core.publisher.MonoFilterFuseable.subscribe(MonoFilterFuseable.java:47)
at reactor.core.publisher.MonoMapFuseable.subscribe(MonoMapFuseable.java:59)
at reactor.core.publisher.MonoFlatMap.subscribe(MonoFlatMap.java:60)
at reactor.core.publisher.Mono.subscribe(Mono.java:3852)
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.drain(FluxConcatMap.java:442)
at reactor.core.publisher.FluxConcatMap$ConcatMapImmediate.onSubscribe(FluxConcatMap.java:212)
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:139)
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:63)
at reactor.core.publisher.FluxConcatMap.subscribe(FluxConcatMap.java:121)
at reactor.core.publisher.MonoNext.subscribe(MonoNext.java:40)
at reactor.core.publisher.MonoDefaultIfEmpty.subscribe(MonoDefaultIfEmpty.java:37)
at reactor.core.publisher.MonoFilter.subscribe(MonoFilter.java:46)
at reactor.core.publisher.MonoSwitchIfEmpty.subscribe(MonoSwitchIfEmpty.java:44)
at reactor.core.publisher.MonoFlatMap.subscribe(MonoFlatMap.java:60)
at reactor.core.publisher.MonoSwitchIfEmpty.subscribe(MonoSwitchIfEmpty.java:44)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
at reactor.core.publisher.MonoOnErrorResume.subscribe(MonoOnErrorResume.java:44)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
at reactor.core.publisher.Mono.subscribe(Mono.java:3852)
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.drain(MonoIgnoreThen.java:172)
at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:56)
at reactor.core.publisher.Mono.subscribe(Mono.java:3852)
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onComplete(FluxSwitchIfEmpty.java:75)
at reactor.core.publisher.FluxFilter$FilterSubscriber.onComplete(FluxFilter.java:160)
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onComplete(FluxSwitchIfEmpty.java:78)
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2073)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.set(Operators.java:1879)
at reactor.core.publisher.Operators$MultiSubscriptionSubscriber.onSubscribe(Operators.java:1753)
at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:54)
at reactor.core.publisher.Mono.subscribe(Mono.java:3852)
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onComplete(FluxSwitchIfEmpty.java:75)
at reactor.core.publisher.MonoNext$NextSubscriber.onComplete(MonoNext.java:96)
at reactor.core.publisher.FluxFilter$FilterSubscriber.onComplete(FluxFilter.java:160)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.checkTerminated(FluxFlatMap.java:794)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.drainLoop(FluxFlatMap.java:560)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.drain(FluxFlatMap.java:540)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.onComplete(FluxFlatMap.java:426)
at reactor.core.publisher.FluxIterable$IterableSubscription.slowPath(FluxIterable.java:265)
at reactor.core.publisher.FluxIterable$IterableSubscription.request(FluxIterable.java:201)
at reactor.core.publisher.FluxFlatMap$FlatMapMain.onSubscribe(FluxFlatMap.java:335)
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:139)
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:63)
at reactor.core.publisher.FluxFlatMap.subscribe(FluxFlatMap.java:97)
at reactor.core.publisher.FluxFilter.subscribe(FluxFilter.java:53)
at reactor.core.publisher.MonoNext.subscribe(MonoNext.java:40)
at reactor.core.publisher.MonoSwitchIfEmpty.subscribe(MonoSwitchIfEmpty.java:44)
at reactor.core.publisher.MonoFilter.subscribe(MonoFilter.java:46)
at reactor.core.publisher.MonoSwitchIfEmpty.subscribe(MonoSwitchIfEmpty.java:44)
at reactor.core.publisher.MonoMap.subscribe(MonoMap.java:55)
at reactor.core.publisher.MonoFlatMap.subscribe(MonoFlatMap.java:60)
at reactor.core.publisher.MonoFlatMap.subscribe(MonoFlatMap.java:60)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:150)
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1515)
at reactor.core.publisher.FluxDefaultIfEmpty$DefaultIfEmptySubscriber.onComplete(FluxDefaultIfEmpty.java:100)
at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:136)
at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:136)
at reactor.core.publisher.FluxFilter$FilterSubscriber.onComplete(FluxFilter.java:160)
at reactor.core.publisher.FluxMap$MapConditionalSubscriber.onComplete(FluxMap.java:262)
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1516)
at reactor.core.publisher.MonoProcessor.subscribe(MonoProcessor.java:457)
at reactor.core.publisher.MonoMap.subscribe(MonoMap.java:52)
at reactor.core.publisher.MonoFilter.subscribe(MonoFilter.java:46)
at reactor.core.publisher.MonoMap.subscribe(MonoMap.java:55)
at reactor.core.publisher.MonoMap.subscribe(MonoMap.java:55)
at reactor.core.publisher.MonoDefaultIfEmpty.subscribe(MonoDefaultIfEmpty.java:37)
at reactor.core.publisher.MonoFlatMap.subscribe(MonoFlatMap.java:60)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
at reactor.core.publisher.Mono.subscribe(Mono.java:3852)
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.drain(MonoIgnoreThen.java:172)
at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:56)
at reactor.core.publisher.Mono.subscribe(Mono.java:3852)
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onComplete(FluxSwitchIfEmpty.java:75)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:141)
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onNext(FluxFilterFuseable.java:113)
at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2071)
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.request(FluxFilterFuseable.java:185)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:103)
at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onSubscribe(FluxFilterFuseable.java:82)
at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:54)
at reactor.core.publisher.MonoFilterFuseable.subscribe(MonoFilterFuseable.java:47)
at reactor.core.publisher.MonoFlatMap.subscribe(MonoFlatMap.java:60)
at reactor.core.publisher.MonoSwitchIfEmpty.subscribe(MonoSwitchIfEmpty.java:44)
at reactor.core.publisher.MonoFlatMap.subscribe(MonoFlatMap.java:60)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
at reactor.core.publisher.MonoSubscriberContext.subscribe(MonoSubscriberContext.java:47)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
at reactor.core.publisher.MonoSubscriberContext.subscribe(MonoSubscriberContext.java:47)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:150)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:121)
at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:121)
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1515)
at reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:241)
at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1515)
at reactor.core.publisher.MonoCollectList$MonoCollectListSubscriber.onComplete(MonoCollectList.java:121)
at reactor.core.publisher.FluxIterable$IterableSubscription.fastPath(FluxIterable.java:333)
at reactor.core.publisher.FluxIterable$IterableSubscription.request(FluxIterable.java:198)
at reactor.core.publisher.MonoCollectList$MonoCollectListSubscriber.onSubscribe(MonoCollectList.java:72)
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:139)
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:63)
at reactor.core.publisher.MonoCollectList.subscribe(MonoCollectList.java:40)
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:150)
at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:67)
at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:76)
at reactor.core.publisher.FluxFilterWhen$FluxFilterWhenSubscriber.drain(FluxFilterWhen.java:295)
at reactor.core.publisher.FluxFilterWhen$FluxFilterWhenSubscriber.onNext(FluxFilterWhen.java:134)
at reactor.core.publisher.FluxIterable$IterableSubscription.slowPath(FluxIterable.java:243)
at reactor.core.publisher.FluxIterable$IterableSubscription.request(FluxIterable.java:201)
at reactor.core.publisher.FluxFilterWhen$FluxFilterWhenSubscriber.onSubscribe(FluxFilterWhen.java:194)
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:139)
at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:63)
at reactor.core.publisher.FluxFilterWhen.subscribe(FluxFilterWhen.java:69)
at reactor.core.publisher.MonoNext.subscribe(MonoNext.java:40)
at reactor.core.publisher.MonoSwitchIfEmpty.subscribe(MonoSwitchIfEmpty.java:44)
at reactor.core.publisher.MonoFlatMap.subscribe(MonoFlatMap.java:60)
at reactor.core.publisher.MonoMapFuseable.subscribe(MonoMapFuseable.java:59)
at reactor.core.publisher.MonoMapFuseable.subscribe(MonoMapFuseable.java:59)
at reactor.core.publisher.MonoFlatMap.subscribe(MonoFlatMap.java:60)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
at reactor.core.publisher.MonoPeekTerminal.subscribe(MonoPeekTerminal.java:61)
at reactor.core.publisher.MonoPeekFuseable.subscribe(MonoPeekFuseable.java:74)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
at reactor.core.publisher.MonoOnErrorResume.subscribe(MonoOnErrorResume.java:44)
at reactor.core.publisher.MonoOnErrorResume.subscribe(MonoOnErrorResume.java:44)
at reactor.core.publisher.MonoPeekTerminal.subscribe(MonoPeekTerminal.java:61)
at reactor.core.publisher.MonoOnErrorResume.subscribe(MonoOnErrorResume.java:44)
at reactor.core.publisher.Mono.subscribe(Mono.java:3852)
at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.drain(MonoIgnoreThen.java:172)
at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:56)
at reactor.core.publisher.MonoPeekFuseable.subscribe(MonoPeekFuseable.java:70)
at reactor.core.publisher.MonoPeekTerminal.subscribe(MonoPeekTerminal.java:61)
at reactor.netty.http.server.HttpServerHandle.onStateChange(HttpServerHandle.java:64)
at reactor.netty.tcp.TcpServerBind$ChildObserver.onStateChange(TcpServerBind.java:226)
at reactor.netty.http.server.HttpServerOperations.onInboundNext(HttpServerOperations.java:442)
at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:91)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at reactor.netty.http.server.HttpTrafficHandler.channelRead(HttpTrafficHandler.java:161)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:438)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:328)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:302)
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:352)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1421)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:374)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:360)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:930)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:697)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:632)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:549)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:511)
at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:918)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:835)
Caused by: org.springframework.security.access.AccessDeniedException: Access Denied
at org.springframework.security.authorization.ReactiveAuthorizationManager.lambda$verify$1(ReactiveAuthorizationManager.java:53)
at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:44)
... 214 more
До сих пор мне удалось перенаправить пользователей к внешнему провайдеру OpenID для аутентификации, используя следующую AuthenticationEntryPoint.А также возможность перенаправления обратно во внешний интерфейс, если пользователь может войти в систему поставщика OpenID.
@Component
public class OpenIDAuthenticationEntryPoint implements ServerAuthenticationEntryPoint {
@Autowired
private OpenIdUtil openIdUtil;
@Override
public Mono<Void> commence(ServerWebExchange serverWebExchange, AuthenticationException e) {
e.printStackTrace();
return openIdUtil.authRequest(serverWebExchange); // invoke openid function
}
}
Класс OpenIdUtil (со ссылкой из SampleConsumer из openid4java)
Log4j2
@Service
public class OpenIdUtil {
private ConsumerManager manager;
public OpenIdUtil() {
// instantiate a ConsumerManager object
manager = new ConsumerManager();
}
/** placing the authentication request **/
public Mono<Void> authRequest(ServerWebExchange serverWebExchange) {
System.out.println("AUTH-REQUEST");
try
{
// configure the return_to URL where your application will receive the authentication responses from the OpenID provider
String returnToUrl = "<return url>";
// perform discovery on the user-supplied identifier
List discoveries = manager.discover("<the url of the external openid provider>");
// attempt to associate with the OpenID provider and retrieve one service endpoint for authentication
DiscoveryInformation discovered = manager.associate(discoveries);
// store the discovery information in the user's session
serverWebExchange.getSession().map(session -> {
session.getAttributes().put("openid-disc", discovered);
return session;
}).subscribe();
// obtain a AuthRequest message to be sent to the OpenID provider
AuthRequest authReq = manager.authenticate(discovered, returnToUrl);
serverWebExchange.getResponse().setStatusCode(HttpStatus.TEMPORARY_REDIRECT);
serverWebExchange.getResponse().getHeaders().setLocation(URI.create(authReq.getDestinationUrl(true)));
return serverWebExchange.getResponse().setComplete();
}
catch (OpenIDException e)
{
// present error to the user
e.printStackTrace();
}
return null;
}
/** processing the authentication response **/
String verifyResponse(ServerWebExchange serverWebExchange) {
try
{
// extract the parameters from the authentication response (which comes in as a HTTP request from the OpenID provider)
MultiValueMap<String, String> queryParams = serverWebExchange.getRequest().getQueryParams();
ParameterList response = new ParameterList(queryParams.toSingleValueMap());
// retrieve the previously stored discovery information
final DiscoveryInformation[] discovered = new DiscoveryInformation[1];
serverWebExchange.getSession().map(session -> discovered[0] = session.getAttribute("openid-disc")).subscribe();
// extract the receiving URL from the HTTP request
String receivingURL = serverWebExchange.getRequest().getURI().toString();
// verify the response; ConsumerManager needs to be the same (static) instance used to place the authentication request
VerificationResult verification = manager.verify(receivingURL, response, discovered[0]);
// examine the verification result and extract the verified identifier
Identifier verified = verification.getVerifiedId();
if (verified != null)
{
return verified.getIdentifier(); // success
}
}
catch (OpenIDException e)
{
// present error to the user
e.printStackTrace();
}
return null;
}
}
Я также создал пользовательский ReactiveAuthenticationManager для ручного выполнения «аутентификации» (ссылаясь на пример Spring Webflux JWT - https://github.com/heesuk-ahn/spring-webflux-jwt-auth-example)
@Component
public class OpenIDReactiveAuthenticationManager implements ReactiveAuthenticationManager {
@Override
public Mono<Authentication> authenticate(Authentication authentication) {
return Mono.just(authentication);
}
}
и ServerAuthenticationConverter для проверки ответа аутентификации OpenId, поступающего от AuthenticationFilter ServerWebExchange.
@Component
public class PreAuthenticationConverter implements ServerAuthenticationConverter {
@Autowired
private OpenIdUtil openIdUtil;
@Override
public Mono<Authentication> convert(ServerWebExchange serverWebExchange) {
try {
String user = URI.create(openIdUtil.verifyResponse(serverWebExchange)).getPath();
// extract credentials here
if (!user.isEmpty()){
SimpleGrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER");
List<SimpleGrantedAuthority> updatedAuthorities = new ArrayList<>();
updatedAuthorities.add(authority);
Authentication authentication = new UsernamePasswordAuthenticationToken(user,null, updatedAuthorities);
return Mono.just(authentication);
}
return Mono.empty();
} catch (Exception e) {
// log error here
return Mono.empty();
}
}
}
И, наконец, класс SecurityConfiguration.
@Configuration
@EnableWebFluxSecurity
@RequiredArgsConstructor
public class SecurityConfiguration {
@Autowired
private PreAuthenticationConverter preAuthenticationConverter;
@Autowired
private OpenIDAuthenticationEntryPoint openIDAuthenticationEntryPoint;
@Autowired
private OpenIDReactiveAuthenticationManager openIDReactiveAuthenticationManager;
SecurityWebFilterChain securityWebFilterChainStg(ServerHttpSecurity http) {
return http.cors()
.and()
.csrf().disable()
.authorizeExchange()
.pathMatchers("/actuator/health", "/actuator/info").permitAll()
.anyExchange().authenticated()
.and()
.addFilterAt(preAuthenticationFilter(), SecurityWebFiltersOrder.AUTHENTICATION)
.exceptionHandling().authenticationEntryPoint(openIDAuthenticationEntryPoint)
.and()
.build();
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Collections.singletonList("*"));
configuration.addAllowedMethod("GET");
configuration.addAllowedMethod("POST");
configuration.addAllowedMethod("DELETE");
configuration.addAllowedHeader("authorization");
configuration.addAllowedHeader("content-type");
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
private AuthenticationWebFilter preAuthenticationFilter(){
AuthenticationWebFilter preAuthenticationFilter = new AuthenticationWebFilter(openIDReactiveAuthenticationManager);
preAuthenticationFilter.setServerAuthenticationConverter(preAuthenticationConverter);
return preAuthenticationFilter;
}
}
Я пробовал различные методы, такие как ручная установка Аутентификации в WebSessionServerSecurityContextRepository, но все же не удалось аутентифицировать пользователя, так как AuthenticationEntryPoint продолжает вызыватьсядля каждого запроса, поступающего от внешнего интерфейса.
ServerSecurityContextRepository serverSecurityContextRepository = new WebSessionServerSecurityContextRepository();
return serverSecurityContextRepository.save(exchange,
new SecurityContextImpl(authentication))
.subscriberContext(ReactiveSecurityContextHolder.withAuthentication(authentication));
Надеясь, что кто-то может дать некоторое представление / руководство о том, почему аутентификация считается не "аутентифицированной" инстобъявление ожидаемого результата, когда пользователь сможет получить доступ к веб-интерфейсу без повторного перенаправления вперед и назад поставщика веб-интерфейса и OpenID с помощью AuthenticationEntryPoint