spring-boot - Spring Boot(微服务)网关在使用 JWT 进行身份验证时失败
问题描述
我用 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]
我不明白这个异常的真正含义,我发现很多人都会遇到相同的异常,但它可能会在不同的情况下抛出。
那里使用了 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 一起使用,但它应该以反应方式配置。
解决方案
新的 Spring Cloud Greendwich.SR5版本提供了一个新属性,用于定义网关中的最大标头大小。
spring.cloud.gateway.httpclient.maxHeaderSize
有了它,您将能够修改 http 响应标头的大小。
推荐阅读
- vue.js - 如何在 Vue 中使按钮的占位符动态化?
- javascript - 如何在 react.js 中创建我们自己的按钮组件,如 antdesign
- flutter - 如何设置文本值以在颤动中自动更改?
- docker - 如何测试 ansible 角色?
- excel - 如何访问 for-each 下的变量结构以在 XSLT 中创建 excel 工作表
- c# - Pass Type as a parameter to template function
- android - 分页在 Android recyclerview 中没有按预期工作
- c++ - 如何使用 libcurl 将图片上传到最重要的服务器?
- matlab - 使用“保存”保存目录时出错
- xen - xl create: 无法检索域配置错误