如何绕过spring webflux security中的一些url?

Posted

技术标签:

【中文标题】如何绕过spring webflux security中的一些url?【英文标题】:How to bypass some urls in spring webflux security? 【发布时间】:2021-08-15 16:12:56 【问题描述】:

我有一个 spring webflux 应用程序并使用以下代码启用了 spring webflux 安全性:-

  public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) 
    log.debug("Configuring tenant web security");
    return http
        .csrf().disable()
        .authorizeExchange()
        .pathMatchers("/actuator/**").permitAll()
        .anyExchange().authenticated()
        .and()
        .addFilterAt(authenticationWebFilter(), SecurityWebFiltersOrder.AUTHENTICATION)
        .addFilterAt(authorizationWebFilter(), SecurityWebFiltersOrder.AUTHORIZATION)
        .build();
  

  private AuthenticationWebFilter authenticationWebFilter() 
    AuthenticationWebFilter authenticationWebFilter = new AuthenticationWebFilter(
        customAuthenticationManager);
    authenticationWebFilter.setServerAuthenticationConverter(customAuthenticationConverter);
    return authenticationWebFilter;
  

  private AuthorizationWebFilter authorizationWebFilter() 
    return new AuthorizationWebFilter(customAuthorizationManager);
  

我想绕过代码中提到的执行器 url,但不知何故,它们仍然进入 ServerAuthenticationConverter 类,我已覆盖该类以解析标题。

我正在请求localhost:8082/actuator/health,它仍在通过所有安全链。

我在这里做错了什么?

以下链接与此问题有关,但找不到任何有用的答案:- How to exclude a path from authentication in a spring based reactive application?

异常调试日志:-

2021-05-27 21:11:50.496 DEBUG 87018 --- [ctor-http-nio-3] io.netty.buffer.AbstractByteBuf          : -Dio.netty.buffer.checkBounds: true
2021-05-27 21:11:50.497 DEBUG 87018 --- [ctor-http-nio-3] i.n.util.ResourceLeakDetectorFactory     : Loaded default ResourceLeakDetector: io.netty.util.ResourceLeakDetector@1afad0f4
2021-05-27 21:11:50.510 DEBUG 87018 --- [ctor-http-nio-3] r.n.http.server.HttpServerOperations     : [id: 0xdbf63e0b, L:/[0:0:0:0:0:0:0:1]:8082 - R:/[0:0:0:0:0:0:0:1]:53830] New http connection, requesting read
2021-05-27 21:11:50.510 DEBUG 87018 --- [ctor-http-nio-2] r.n.http.server.HttpServerOperations     : [id: 0x3302bee3, L:/[0:0:0:0:0:0:0:1]:8082 - R:/[0:0:0:0:0:0:0:1]:53829] New http connection, requesting read
2021-05-27 21:11:50.510 DEBUG 87018 --- [ctor-http-nio-2] reactor.netty.transport.TransportConfig  : [id: 0x3302bee3, L:/[0:0:0:0:0:0:0:1]:8082 - R:/[0:0:0:0:0:0:0:1]:53829] Initialized pipeline DefaultChannelPipeline(reactor.left.httpCodec = io.netty.handler.codec.http.HttpServerCodec), (reactor.left.httpTrafficHandler = reactor.netty.http.server.HttpTrafficHandler), (reactor.right.reactiveBridge = reactor.netty.channel.ChannelOperationsHandler)
2021-05-27 21:11:50.510 DEBUG 87018 --- [ctor-http-nio-3] reactor.netty.transport.TransportConfig  : [id: 0xdbf63e0b, L:/[0:0:0:0:0:0:0:1]:8082 - R:/[0:0:0:0:0:0:0:1]:53830] Initialized pipeline DefaultChannelPipeline(reactor.left.httpCodec = io.netty.handler.codec.http.HttpServerCodec), (reactor.left.httpTrafficHandler = reactor.netty.http.server.HttpTrafficHandler), (reactor.right.reactiveBridge = reactor.netty.channel.ChannelOperationsHandler)
2021-05-27 21:11:50.516 DEBUG 87018 --- [ctor-http-nio-3] io.netty.util.Recycler                   : -Dio.netty.recycler.maxCapacityPerThread: 4096
2021-05-27 21:11:50.516 DEBUG 87018 --- [ctor-http-nio-3] io.netty.util.Recycler                   : -Dio.netty.recycler.maxSharedCapacityFactor: 2
2021-05-27 21:11:50.516 DEBUG 87018 --- [ctor-http-nio-3] io.netty.util.Recycler                   : -Dio.netty.recycler.linkCapacity: 16
2021-05-27 21:11:50.516 DEBUG 87018 --- [ctor-http-nio-3] io.netty.util.Recycler                   : -Dio.netty.recycler.ratio: 8
2021-05-27 21:11:50.516 DEBUG 87018 --- [ctor-http-nio-3] io.netty.util.Recycler                   : -Dio.netty.recycler.delayedQueue.ratio: 8
2021-05-27 21:11:50.542 DEBUG 87018 --- [ctor-http-nio-3] r.n.http.server.HttpServerOperations     : [id: 0xdbf63e0b, L:/[0:0:0:0:0:0:0:1]:8082 - R:/[0:0:0:0:0:0:0:1]:53830] Increasing pending responses, now 1
2021-05-27 21:11:50.547 DEBUG 87018 --- [ctor-http-nio-3] reactor.netty.http.server.HttpServer     : [id: 0xdbf63e0b, L:/[0:0:0:0:0:0:0:1]:8082 - R:/[0:0:0:0:0:0:0:1]:53830] Handler is being applied: org.springframework.http.server.reactive.ReactorHttpHandlerAdapter@60ba6618
2021-05-27 21:11:50.553 DEBUG 87018 --- [ctor-http-nio-3] o.s.w.s.adapter.HttpWebHandlerAdapter    : [dbf63e0b-1] HTTP GET "/actuator/health"
2021-05-27 21:11:50.589  WARN 87018 --- [ctor-http-nio-3] c.r.c.a.c.e.RestWebExceptionHandler      : Web request for uri http://localhost:8082/actuator/health failed with exception java.lang.IllegalArgumentException: X-Auth header is not present.
    at com.demo.ceresgateway.app.config.security.CustomServerAuthenticationConverter.resolveHeaders(CustomServerAuthenticationConverter.java:61)
    Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException: 
Error has been observed at the following site(s):
    |_ checkpoint ⇢ org.springframework.security.web.server.authentication.AuthenticationWebFilter [DefaultWebFilterChain]
    |_ checkpoint ⇢ org.springframework.security.web.server.context.ReactorContextWebFilter [DefaultWebFilterChain]
    |_ checkpoint ⇢ org.springframework.security.web.server.header.HttpHeaderWriterWebFilter [DefaultWebFilterChain]
    |_ checkpoint ⇢ org.springframework.security.config.web.server.ServerHttpSecurity$ServerWebExchangeReactorContextWebFilter [DefaultWebFilterChain]
    |_ checkpoint ⇢ org.springframework.security.web.server.WebFilterChainProxy [DefaultWebFilterChain]
    |_ checkpoint ⇢ org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter [DefaultWebFilterChain]
    |_ checkpoint ⇢ HTTP GET "/actuator/health" [ExceptionHandlingWebHandler]
Stack trace:
        at com.demo.ceresgateway.app.config.security.CustomServerAuthenticationConverter.resolveHeaders(CustomServerAuthenticationConverter.java:61)
        at com.demo.ceresgateway.app.config.security.CustomServerAuthenticationConverter.convert(CustomServerAuthenticationConverter.java:31)
        at org.springframework.security.web.server.authentication.AuthenticationWebFilter.lambda$filter$2(AuthenticationWebFilter.java:112)
        at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:125)
        at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onNext(FluxFilterFuseable.java:118)
        at reactor.core.publisher.Operators$ScalarSubscription.request(Operators.java:2346)
        at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.request(FluxFilterFuseable.java:191)
        at reactor.core.publisher.MonoFlatMap$FlatMapMain.onSubscribe(MonoFlatMap.java:110)
        at reactor.core.publisher.FluxFilterFuseable$FilterFuseableSubscriber.onSubscribe(FluxFilterFuseable.java:87)
        at reactor.core.publisher.MonoJust.subscribe(MonoJust.java:54)
        at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
        at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
        at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
        at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
        at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
        at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
        at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
        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:157)
        at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:127)
        at reactor.core.publisher.FluxMapFuseable$MapFuseableSubscriber.onNext(FluxMapFuseable.java:127)
        at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1784)
        at reactor.core.publisher.MonoFlatMap$FlatMapInner.onNext(MonoFlatMap.java:249)
        at reactor.core.publisher.Operators$MonoSubscriber.complete(Operators.java:1784)
        at reactor.core.publisher.MonoCollectList$MonoCollectListSubscriber.onComplete(MonoCollectList.java:128)
        at reactor.core.publisher.FluxIterable$IterableSubscription.fastPath(FluxIterable.java:360)
        at reactor.core.publisher.FluxIterable$IterableSubscription.request(FluxIterable.java:225)
        at reactor.core.publisher.MonoCollectList$MonoCollectListSubscriber.onSubscribe(MonoCollectList.java:79)
        at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:164)
        at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:86)
        at reactor.core.publisher.MonoFromFluxOperator.subscribe(MonoFromFluxOperator.java:81)
        at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:157)
        at reactor.core.publisher.FluxSwitchIfEmpty$SwitchIfEmptySubscriber.onNext(FluxSwitchIfEmpty.java:73)
        at reactor.core.publisher.MonoNext$NextSubscriber.onNext(MonoNext.java:82)
        at reactor.core.publisher.FluxFilterWhen$FluxFilterWhenSubscriber.drain(FluxFilterWhen.java:301)
        at reactor.core.publisher.FluxFilterWhen$FluxFilterWhenSubscriber.onNext(FluxFilterWhen.java:140)
        at reactor.core.publisher.FluxIterable$IterableSubscription.slowPath(FluxIterable.java:270)
        at reactor.core.publisher.FluxIterable$IterableSubscription.request(FluxIterable.java:228)
        at reactor.core.publisher.FluxFilterWhen$FluxFilterWhenSubscriber.onSubscribe(FluxFilterWhen.java:200)
        at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:164)
        at reactor.core.publisher.FluxIterable.subscribe(FluxIterable.java:86)
        at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
        at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
        at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
        at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
        at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
        at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:52)
        at reactor.core.publisher.Mono.subscribe(Mono.java:4046)
        at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.drain(MonoIgnoreThen.java:173)
        at reactor.core.publisher.MonoIgnoreThen.subscribe(MonoIgnoreThen.java:56)
        at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:64)
        at reactor.netty.http.server.HttpServer$HttpServerHandle.onStateChange(HttpServer.java:632)
        at reactor.netty.ReactorNetty$CompositeConnectionObserver.onStateChange(ReactorNetty.java:612)
        at reactor.netty.transport.ServerTransport$ChildObserver.onStateChange(ServerTransport.java:453)
        at reactor.netty.http.server.HttpServerOperations.onInboundNext(HttpServerOperations.java:510)
        at reactor.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:94)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
        at reactor.netty.http.server.HttpTrafficHandler.channelRead(HttpTrafficHandler.java:208)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
        at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
        at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:324)
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:296)
        at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
        at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:719)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:655)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:581)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
        at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
        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:832)

2021-05-27 21:11:50.595 DEBUG 87018 --- [ctor-http-nio-3] a.w.r.e.AbstractErrorWebExceptionHandler : [dbf63e0b-1] Resolved [IllegalArgumentException: Only one of (X-Auth-Token) or (X-Username, X-Api-Key/X-Password) headers should be present at a time and when giving X-Username only one of X-Api-Key or X-Password header should be present.] for HTTP GET /actuator/health
2021-05-27 21:11:50.611 DEBUG 87018 --- [ctor-http-nio-3] o.s.http.codec.json.Jackson2JsonEncoder  : [dbf63e0b-1] Encoding [timestamp=Thu May 27 21:11:50 IST 2021, path=/actuator/health, status=400, message=Only one of (X-A (truncated)...]
2021-05-27 21:11:50.656 DEBUG 87018 --- [ctor-http-nio-3] r.n.http.server.HttpServerOperations     : [id: 0xdbf63e0b, L:/[0:0:0:0:0:0:0:1]:8082 - R:/[0:0:0:0:0:0:0:1]:53830] Decreasing pending responses, now 0
2021-05-27 21:11:50.660 DEBUG 87018 --- [ctor-http-nio-3] r.n.http.server.HttpServerOperations     : [id: 0xdbf63e0b, L:/[0:0:0:0:0:0:0:1]:8082 - R:/[0:0:0:0:0:0:0:1]:53830] Last HTTP packet was sent, terminating the channel
2021-05-27 21:11:50.660 DEBUG 87018 --- [ctor-http-nio-3] o.s.w.s.adapter.HttpWebHandlerAdapter    : [dbf63e0b-1] Completed 400 BAD_REQUEST
2021-05-27 21:11:50.662 DEBUG 87018 --- [ctor-http-nio-3] r.n.http.server.HttpServerOperations     : [id: 0xdbf63e0b, L:/[0:0:0:0:0:0:0:1]:8082 - R:/[0:0:0:0:0:0:0:1]:53830] Last HTTP response frame

【问题讨论】:

使用 Spring Security 服务器调试日志和您提出的请求更新您的问题。 我已经更新了我的问题 看不到任何调试日志。 更新了调试日志 像您所做的那样禁用安全性意味着一些弹簧内部过滤器将被禁用。这并不意味着过滤器链中的每个过滤器都被禁用。您已构建自定义过滤器,这意味着您已选择不使用框架中提供的功能。我的建议是,如果您希望能够利用排除等功能,您可以自定义内置过滤器的弹簧。您的另一个选择是在自定义过滤器中构建排除项。我个人认为自定义安全过滤器是不好的做法。所有自定义安全都是不好的做法。 【参考方案1】:

您无需在配置中手动添加AuthenticationWebFilterAuthorizationWebFilter

实现您想要的更现代的方法通常是这样:

@Bean
SecurityWebFilterChain springWebFilterChain(ServerHttpSecurity http) 
    http
        .authorizeExchange((exchanges) -> exchanges
            .pathMatchers("/actuator/**").permitAll()
            .anyExchange().authenticated()
        )
        .csrf().disable();

    return http.build();

您可以在Spring Security docs中找到有关安全配置的更多信息

【讨论】:

我添加了 AuthenticationWebFilter 和 AuthorizationWebFilter 来提供一些自定义实现。

以上是关于如何绕过spring webflux security中的一些url?的主要内容,如果未能解决你的问题,请参考以下文章

spring5 webflux,如何返回自定义json数据?

如何在 Spring boot 2 + Webflux + Thymeleaf 中配置 i18n?

如何使用 Spring Boot 对 WebFlux 进行异常处理?

如何使用 spring webflux 读取请求正文

如何将 ModelAndView Spring MVC 转换为 Spring Webflux

如何在spring-webflux中获取当前请求的上下文