我正在尝试使用Vuejs前端在反应式Spring Boot应用程序中配置Spring Security,以在未经身份验证时将用户重定向到外部OpenID提供程序(用于身份验证)。使用OpenID提供程序对用户进行身份验证并重定向回应用程序(前端)后,将基于OpenID提供程序的响应创建UsernamePasswordAuthenticationToken(身份验证),并对其进行手动身份验证。
但是,这样做时,应用程序似乎无法检测到用户已通过身份验证,因为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
到目前为止,我已经通过利用以下AuthenticationEntryPoint将用户重定向到外部OpenID提供程序进行身份验证。如果用户能够登录到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类(参考openid4java的SampleConsumer)
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来验证来自AuthenticationFilter ServerWebExchange的OpenId身份验证响应。
@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; } }
我尝试了各种方法,例如将Authentication手动设置到WebSessionServerSecurityContextRepository中,但是由于AuthenticationEntryPoint不断为来自前端的每个请求调用,因此仍然无法对用户进行身份验证。
ServerSecurityContextRepository serverSecurityContextRepository = new WebSessionServerSecurityContextRepository(); return serverSecurityContextRepository.save(exchange, new SecurityContextImpl(authentication)) .subscriberContext(ReactiveSecurityContextHolder.withAuthentication(authentication));
希望某人可以提供一些见解/指南,说明为什么认为认证未经过“认证”,而不是预期的结果,即用户将能够访问前端而无需由前端反复来回重定向前端和OpenID提供程序的AuthenticationEntryPoint
我正在尝试使用Vuejs前端在反应式Spring Boot应用程序中配置Spring Security,以在未经身份验证时将用户重定向到外部OpenID提供程序(用于身份验证)。 ...
很难知道出什么问题了,因为我无法运行您的代码,并且您将命令式编程与反应式编程混合在一起。