简体   繁体   English

Spring Boot(微服务)网关在使用 JWT 进行身份验证时失败

[英]Spring Boot (Microservices) Gateway fails on authentication with JWT

I have built a micro service gateway with Spring Boot Gateway and it works.我已经使用 Spring Boot Gateway 构建了一个微服务网关并且它可以工作。 Next I added security, but I cannot make gateway forward authentication request to authenticator microservice.接下来我添加了安全性,但我无法向身份验证器微服务发出网关转发身份验证请求。 How to forward request to authenticator micro service?如何将请求转发到身份验证器微服务? As I understand request fails in gateway.据我了解,请求在网关中失败。 Here I describe what I did and source codes are on git:在这里,我描述了我所做的事情,并且源代码在 git 上:

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

Here the request auth.sh I use to authenticate这里是我用来认证的请求 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

and it outputs to console:它输出到控制台:

{ "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

I tried to put break points and get where is the problem in both gateway and authenticator, but it not helps, as any breakpoints in my application classes not executed.我试图放置断点并找出网关和身份验证器中的问题所在,但这没有帮助,因为我的应用程序类中的任何断点都没有执行。 Only when I set logs to debug I found in logs an exception:只有当我将日志设置为调试时,我才在日志中发现异常:

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]

I do not understand what this exception could really mean, and I found a lot of people get same exception but it could be thrown in different cases.我不明白这个异常的真正含义,我发现很多人都会遇到相同的异常,但它可能会在不同的情况下抛出。

To build the gateway I mostly follow the guide on https://medium.com/omarelgabrys-blog/microservices-with-spring-boot-authentication-with-jwt-part-3-fafc9d7187e8为了构建网关,我主要遵循https://medium.com/omarelgabrys-blog/microservices-with-spring-boot-authentication-with-jwt-part-3-fafc9d7187e8上的指南

There used Zuul but not Spring cloud gateway, though as I have my gateway worked before, and know how to build routes it should be fine.使用了 Zuul 但没有使用 Spring 云网关,尽管我的网关以前工作过,并且知道如何构建路由应该没问题。 Just one thing in ZUUL config , I not found what to do with is:在 ZUUL config 中只有一件事,我没有找到要做的事情是:

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

Update Added debug log.更新添加了调试日志。 It contains application load and one curl call described on top of this post.它包含应用程序负载和本文顶部描述的一个 curl 调用。 Caution!警告! file size more than 1 mb文件大小超过 1 mb

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

Update I tried to simplify gateway, to catch where problem is.更新我试图简化网关,以找出问题所在。 I commented out spring-boot-starter-security dependency and security classes, also I have to comment out spring-boot-starter-tomcat dependency.我注释掉了spring-boot-starter-security依赖项和安全类,我还必须注释掉spring-boot-starter-tomcat依赖项。 And gateway works.和网关工作。 Once I import Tomcat with maven I got an error on request:使用 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]

And after that I found the thread, which seems like say TomCat incompatible with spring-cloud-gatewayhttps://github.com/spring-cloud/spring-cloud-gateway/issues/145之后我找到了这个线程,它似乎说 TomCat 与 spring-cloud-gateway 不兼容https://github.com/spring-cloud/spring-cloud-gateway/issues/145

Then this makes leads to be impossible spring-cloud-gateway to work with Spring Security either, because of OncePerRequest filter method description needs HTTPServletRequest, HttpServletResponse and I import TomCat to have them in class path然后这导致 spring-cloud-gateway 也无法与 Spring Security 一起使用,因为 OncePerRequest 过滤器方法描述需要 HTTPServletRequest、HttpServletResponse 并且我导入 TomCat 以将它们放在类路径中

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

Update Actually Spring Security seems to be possible to use with Spring Cloud Gateway, but it should be configured in reactive manner.更新实际上 Spring Security 似乎可以与 Spring Cloud Gateway 一起使用,但它应该以反应方式进行配置。

New Spring Cloud Greendwich.SR5 release provides a new property for defining the maximum header size in the Gateway.新的 Spring Cloud Greendwich.SR5版本提供了一个新属性,用于定义网关中的最大标头大小。

spring.cloud.gateway.httpclient.maxHeaderSize

With that you will be able to modify the http response header size.有了它,您将能够修改 http 响应标头大小。

Here you have the commit with the changes: https://github.com/spring-cloud/spring-cloud-gateway/commit/64a579d68d3be975a72e639c7cc123a756e21a28在这里,您提交了更改: https : //github.com/spring-cloud/spring-cloud-gateway/commit/64a579d68d3be975a72e639c7cc123a756e21a28

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM