2

我用 Spring Boot Gateway 构建了一个微服务网关,它可以工作。接下来我添加了安全性,但我无法将网关转发身份验证请求发送到身份验证器微服务。如何将请求转发到身份验证器微服务?据我了解,请求在网关中失败。在这里,我描述了我所做的事情,源代码在 git 上:

https://github.com/pavelmorozov/SpringBootGateway , https://github.com/pavelmorozov/EurekaServer , https://github.com/pavelmorozov/ConfigMicroService , https://github.com/pavelmorozov/AuthenticatorMicroService

这里是我用来验证的请求 auth.sh

user="omar"
pass="12345"

generate_post_data()
{
cat <<EOF
{
    "username": "$user",
    "password": "$pass"
}
EOF
}

echo $(generate_post_data)

echo "======================"
echo "http://localhost:8060/auth"
echo "======================"

# -v verbose
curl -v -H 'Access-Control-Request-Method: POST' \
    -H "Content-Type: application/json" \
    "http://localhost:8060/auth/" \
    -d "$(generate_post_data)"

echo

它输出到控制台:

{ "username": "omar", "password": "12345" }
======================
http://localhost:8060/auth
======================
*   Trying 127.0.0.1...
* Connected to localhost (127.0.0.1) port 8060 (#0)
> POST /auth/ HTTP/1.1
> Host: localhost:8060
> User-Agent: curl/7.47.0
> Accept: */*
> Access-Control-Request-Method: POST
> Content-Type: application/json
> Content-Length: 45
> 
* upload completely sent off: 45 out of 45 bytes
< HTTP/1.1 403 
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Content-Type-Options: nosniff
< X-Frame-Options: DENY
< X-XSS-Protection: 1 ; mode=block
< Content-Type: text/plain
< Transfer-Encoding: chunked
< Date: Tue, 25 Sep 2018 18:52:33 GMT
< 
* Connection #0 to host localhost left intact
CSRF Token has been associated to this client

我试图设置断点并找出网关和身份验证器中的问题所在,但这无济于事,因为我的应用程序类中的任何断点都没有执行。只有当我将日志设置为调试时,我才在日志中发现异常:

2018-09-25 21:52:33 DEBUG [-,,,] Error parsing HTTP request header
java.io.EOFException: null
    at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.fillReadBuffer(NioEndpoint.java:1289) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.read(NioEndpoint.java:1223) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.coyote.http11.Http11InputBuffer.fill(Http11InputBuffer.java:729) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.coyote.http11.Http11InputBuffer.parseRequestLine(Http11InputBuffer.java:368) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:684) ~[tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:60) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:806) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1498) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [na:1.8.0_171]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [na:1.8.0_171]
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.34.jar:8.5.34]
    at java.lang.Thread.run(Thread.java:748) [na:1.8.0_171]

我不明白这个异常的真正含义,我发现很多人都会遇到相同的异常,但它可能会在不同的情况下抛出。

要构建网关,我主要遵循https://medium.com/omarelgabrys-blog/microservices-with-spring-boot-authentication-with-jwt-part-3-fafc9d7187e8上的指南

那里使用了 Zuul 但没有使用 Spring 云网关,尽管我的网关以前工作过,并且知道如何构建路由应该没问题。ZUUL config 中只有一件事,我没有找到该怎么做:

# Exclude authorization from sensitive headers
zuul.routes.auth-service.sensitive-headers=Cookie,Set-Cookie   

更新添加了调试日志。它包含应用程序负载和本文顶部描述的一个 curl 调用。警告!文件大小超过 1 mb

https://raw.githubusercontent.com/pavelmorozov/SpringBootGateway/master/doc/debug.log

更新我试图简化网关,以找出问题所在。我注释掉了spring-boot-starter-security依赖和安全类,我也必须注释掉spring-boot-starter-tomcat依赖。网关工作。使用 maven 导入 Tomcat 后,请求时出现错误:

2018-09-26 13:57:07 -ERROR Failed to handle request [GET http://localhost:8060/banquet/api/event/getThemes]
java.lang.ClassCastException: org.springframework.core.io.buffer.DefaultDataBufferFactory cannot be cast to org.springframework.core.io.buffer.NettyDataBufferFactory
    at org.springframework.cloud.gateway.filter.NettyWriteResponseFilter.lambda$filter$0(NettyWriteResponseFilter.java:71) ~[spring-cloud-gateway-core-2.0.1.RELEASE.jar:2.0.1.RELEASE]
    at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:45) [reactor-core-3.1.9.RELEASE.jar:3.1.9.RELEASE]
    at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.drain(MonoIgnoreThen.java:153) ~[reactor-core-3.1.9.RELEASE.jar:3.1.9.RELEASE]
    at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.ignoreDone(MonoIgnoreThen.java:190) ~[reactor-core-3.1.9.RELEASE.jar:3.1.9.RELEASE]
    at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreInner.onComplete(MonoIgnoreThen.java:239) ~[reactor-core-3.1.9.RELEASE.jar:3.1.9.RELEASE]
    at reactor.core.publisher.Operators$MonoSubscriber.onComplete(Operators.java:1121) ~[reactor-core-3.1.9.RELEASE.jar:3.1.9.RELEASE]
    at reactor.core.publisher.MonoIgnoreThen$ThenAcceptInner.onComplete(MonoIgnoreThen.java:313) ~[reactor-core-3.1.9.RELEASE.jar:3.1.9.RELEASE]
    at reactor.core.publisher.Operators.complete(Operators.java:128) [reactor-core-3.1.9.RELEASE.jar:3.1.9.RELEASE]
    at reactor.core.publisher.MonoEmpty.subscribe(MonoEmpty.java:45) ~[reactor-core-3.1.9.RELEASE.jar:3.1.9.RELEASE]
    at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) [reactor-core-3.1.9.RELEASE.jar:3.1.9.RELEASE]
    at reactor.core.publisher.MonoDefer.subscribe(MonoDefer.java:53) [reactor-core-3.1.9.RELEASE.jar:3.1.9.RELEASE]
    at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.drain(MonoIgnoreThen.java:153) ~[reactor-core-3.1.9.RELEASE.jar:3.1.9.RELEASE]
    at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreMain.ignoreDone(MonoIgnoreThen.java:190) ~[reactor-core-3.1.9.RELEASE.jar:3.1.9.RELEASE]
    at reactor.core.publisher.MonoIgnoreThen$ThenIgnoreInner.onComplete(MonoIgnoreThen.java:239) ~[reactor-core-3.1.9.RELEASE.jar:3.1.9.RELEASE]
    at reactor.core.publisher.FluxPeek$PeekSubscriber.onComplete(FluxPeek.java:245) ~[reactor-core-3.1.9.RELEASE.jar:3.1.9.RELEASE]
    at reactor.core.publisher.FluxMap$MapSubscriber.onComplete(FluxMap.java:130) ~[reactor-core-3.1.9.RELEASE.jar:3.1.9.RELEASE]
    at reactor.core.publisher.FluxRetryPredicate$RetryPredicateSubscriber.onComplete(FluxRetryPredicate.java:107) ~[reactor-core-3.1.9.RELEASE.jar:3.1.9.RELEASE]
    at reactor.core.publisher.MonoCreate$DefaultMonoSink.success(MonoCreate.java:147) ~[reactor-core-3.1.9.RELEASE.jar:3.1.9.RELEASE]
    at reactor.ipc.netty.channel.PooledClientContextHandler.fireContextActive(PooledClientContextHandler.java:87) ~[reactor-netty-0.7.9.RELEASE.jar:0.7.9.RELEASE]
    at reactor.ipc.netty.http.client.HttpClientOperations.onInboundNext(HttpClientOperations.java:584) ~[reactor-netty-0.7.9.RELEASE.jar:0.7.9.RELEASE]
    at reactor.ipc.netty.channel.ChannelOperationsHandler.channelRead(ChannelOperationsHandler.java:138) ~[reactor-netty-0.7.9.RELEASE.jar:0.7.9.RELEASE]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) ~[netty-transport-4.1.29.Final.jar:4.1.29.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) ~[netty-transport-4.1.29.Final.jar:4.1.29.Final]
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) ~[netty-transport-4.1.29.Final.jar:4.1.29.Final]
    at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:438) ~[netty-transport-4.1.29.Final.jar:4.1.29.Final]
    at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:310) ~[netty-codec-4.1.29.Final.jar:4.1.29.Final]
    at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:297) ~[netty-codec-4.1.29.Final.jar:4.1.29.Final]
    at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:413) ~[netty-codec-4.1.29.Final.jar:4.1.29.Final]
    at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:265) ~[netty-codec-4.1.29.Final.jar:4.1.29.Final]
    at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:253) ~[netty-transport-4.1.29.Final.jar:4.1.29.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) ~[netty-transport-4.1.29.Final.jar:4.1.29.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) ~[netty-transport-4.1.29.Final.jar:4.1.29.Final]
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) ~[netty-transport-4.1.29.Final.jar:4.1.29.Final]
    at io.netty.handler.logging.LoggingHandler.channelRead(LoggingHandler.java:241) ~[netty-handler-4.1.29.Final.jar:4.1.29.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) ~[netty-transport-4.1.29.Final.jar:4.1.29.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) ~[netty-transport-4.1.29.Final.jar:4.1.29.Final]
    at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) ~[netty-transport-4.1.29.Final.jar:4.1.29.Final]
    at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1434) ~[netty-transport-4.1.29.Final.jar:4.1.29.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) ~[netty-transport-4.1.29.Final.jar:4.1.29.Final]
    at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) ~[netty-transport-4.1.29.Final.jar:4.1.29.Final]
    at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:965) ~[netty-transport-4.1.29.Final.jar:4.1.29.Final]
    at io.netty.channel.epoll.AbstractEpollStreamChannel$EpollStreamUnsafe.epollInReady(AbstractEpollStreamChannel.java:808) ~[netty-transport-native-epoll-4.1.29.Final-linux-x86_64.jar:4.1.29.Final]
    at io.netty.channel.epoll.EpollEventLoop.processReady(EpollEventLoop.java:410) ~[netty-transport-native-epoll-4.1.29.Final-linux-x86_64.jar:4.1.29.Final]
    at io.netty.channel.epoll.EpollEventLoop.run(EpollEventLoop.java:310) ~[netty-transport-native-epoll-4.1.29.Final-linux-x86_64.jar:4.1.29.Final]
    at io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:884) ~[netty-common-4.1.29.Final.jar:4.1.29.Final]
    at java.lang.Thread.run(Thread.java:748) ~[na:1.8.0_171]

之后我找到了线程,好像说 TomCat 与 spring-cloud-gateway 不兼容https://github.com/spring-cloud/spring-cloud-gateway/issues/145

然后这导致 spring-cloud-gateway 也无法与 Spring Security 一起使用,因为 OncePerRequest 过滤器方法描述需要 HTTPServletRequest、HttpServletResponse 并且我导入 TomCat 以将它们放在类路径中

protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)

更新实际上 Spring Security 似乎可以与 Spring Cloud Gateway 一起使用,但它应该以反应方式配置。

4

1 回答 1

1

新的 Spring Cloud Greendwich.SR5版本提供了一个新属性,用于定义网关中的最大标头大小。

spring.cloud.gateway.httpclient.maxHeaderSize

有了它,您将能够修改 http 响应标头的大小。

在这里你有更改的提交:https ://github.com/spring-cloud/spring-cloud-gateway/commit/64a579d68d3be975a72e639c7cc123a756e21a28

于 2020-02-04T16:49:38.827 回答