Spring Boot(Microservices)网关无法通过JWT进行身份验证

时间:2018-09-25 19:57:18

标签: spring-boot spring-security jwt spring-cloud spring-cloud-gateway

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

https://github.com/pavelmorozov/SpringBootGatewayhttps://github.com/pavelmorozov/EurekaServerhttps://github.com/pavelmorozov/ConfigMicroServicehttps://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一起使用,但是应该以反应方式进行配置。

1 个答案:

答案 0 :(得分:1)

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

spring.cloud.gateway.httpclient.maxHeaderSize

这样您就可以修改http响应标头的大小。

您在此处进行了更改:https://github.com/spring-cloud/spring-cloud-gateway/commit/64a579d68d3be975a72e639c7cc123a756e21a28