Vert.x JWT 段数不够或太多

Posted

技术标签:

【中文标题】Vert.x JWT 段数不够或太多【英文标题】:Vert.x JWT Not enough or too many segments 【发布时间】:2018-05-06 18:14:05 【问题描述】:

当我的应用程序从通过 KeyCloak 进行身份验证的前端应用程序接收到 JWT 令牌时,我不断收到错误消息。我得到的错误是“段不够或太多”。据我所知,令牌是一个有效的令牌,应该能够被验证,但我无法克服这个非常普遍的错误。有人可以帮我看看我做错了什么吗?

这是失败的代码的相关sn-p。请注意,在运行我的测试用例时,相同的代码可以正常工作,它使用 vert.x JWTAuth 提供程序来生成令牌:

JWTAuth authProvider = JWTAuth.create(vertx, new JWTAuthOptions(new JsonObject()
    .put("permissionsClaimKey", "realm_access/roles")
    .put("pubSecKeys", new JsonObject()
            .put("publicKey", "vcVtWG5Qcz9gTMrDPfJSWNAiXsyCyBmNIzjtfHhBDX-l60KHyFaGBGBjRNkzDysV6pr6drQR8zRD8ePo8q73KDbXlZohXkR_J-gXer8H5EyWGl7KAATmKvuiYYv89f_C6f3NYUgfyKn6wzUtlsZN1CYpGmbnfLZYUcGzwvWWkddqQUroRrsf305Z17Pioegd_JMhcdprC1caOCuJHe46bYlu4_9m_MSPvBUCqjqAUIDZpB8HT9xrwxlwKG_Er6l-7TvQ32jp0wPxitLpEUg9noAt5w2NXIX44PCSkOdtGxGpj7fhyfivi_HQEfTq3Y4N2BRWAQxXYRaHlgl08CIsLb5rgJXmh8O7506V0THyLcJZ3pTn0u_4KxedOTsEbM_07W8kNCXVQrTIn4Zkyz42geRfblAzjvScP962DzEqu28WVZXWUyJIeQA_z3UM0l-MpQFtFDHsb0inQdeBfA6IN_eRp-JZaoMKLfswUEXjEj6nytKnwOEaqdqq56uPPK1j7QorIjMyn9VztH1WbbWM_JNPNc5CDAjFxo54tvrzqKkxLNbR1lP8g5GbIBeGSRc36IXQEp2hV42i3Pu-7bPJ_E0m9vr5dePjeRotthDUR7osmhOlzqHrLq1uzUYYneK37j7lLMx7N67rkWWMBa3v0h57pVD9ufAd-BxHiQzZL2U")
            .put("type", "RS256"))));

...

versionOneAPI.route().handler(ctx -> 
    String authHeader = ctx.request().getHeader("Authorization");
    String encodedToken = authHeader.substring(authHeader.indexOf(' ')+1);
    LOGGER.debug("Got the token ", encodedToken);
    authProvider.authenticate(new JsonObject().put("jwt", encodedToken), res -> 
        LOGGER.debug("Request received for: ", ctx.request().path());
        if (res.succeeded()) 
            LOGGER.debug("Got the user  from the token", res.result().principal().getString("name"));
            ctx.setUser(res.result());
            ctx.response().putHeader(CONTENT_TYPE, APPLICATION_JSON.toString());
            ctx.next();
        
        else 
            LOGGER.error("Failed to parse token with  segments", encodedToken.split("\\.").length, res.cause());
            ctx.response().setStatusCode(UNAUTHORIZED.code()).setStatusMessage(UNAUTHORIZED.reasonPhrase()).end();
        
    );
);

这是显示失败的日志示例:

15:22:14.930 [main] 调试 groovyx.net.http.RESTClient - POST http://localhost:8080/rest/v1/referrals 15:22:15.069 [vert.x-eventloop-thread-0] 调试 com.redhat.rhambassador.MainVerticle - 拿到令牌eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJscVRYamlvRU9HbnBPenVLSllJOGs4VXFUTThSanBKOWc2bmVIb3pXVm9nIn0.eyJqdGkiOiIzODJiN2Q3OS00MTlkLTQ1ZDItYmU4NS0zY2JkZDA0YTg2ZmQiLCJleHAiOjE1MTEzNjk0NTAsIm5iZiI6MCwiaWF0IjoxNTExMzY5MTUwLCJpc3MiOiJodHRwczovL2V4YW1wbGUuY29tL2F1dGgvcmVhbG1zL0VtcGxveWVlSURQIiwiYXVkIjoiaHR0cHM6Ly9leGFtcGxlLmNvbSIsInN1YiI6ImUwYzc4MTY5LTMyYWUtNDQ1Yy05YWYxLWUwYmVlYjI2YTgxNCIsInR5cCI6IkJlYXJlciIsImF6cCI6Imh0dHBzOi8vZXhhbXBsZS5jb20iLCJub25jZSI6ImY4MjYzNDU5LWJlYTgtNGQzMi04ODBjLTcxNGNhMjdiMGM2NSIsImF1dGhfdGltZSI6MTUxMTM2NjY0Niwic2Vzc2lvbl9zdGF0ZSI6IjVlYTgyMTA3LTI0MWMtNGViMy04MWY3LWU4ZmMxM2E3MWQ5MSIsImFjciI6IjAiLCJjbGllbnRfc2Vzc2lvbiI6IjA1MzUxYjU4LTcyODItNDgxZS1iMjk2LTFjNDExYjUzMmI2NCIsImFsbG93ZWQtb3JpZ2lucyI6WyJodHRwczovL2V4YW1wbGUuY29tIl0sInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6WyJFbXBsb3llZSJdfSwicmVzb3VyY2VfYWNjZXNzIjp7ImFjY291bnQiOnsicm9sZXMiOlsibWFuYWdlLWFjY291bnQiLCJ2aWV3LXByb2ZpbGUiXX19LCJsYXN0TmFtZSI6IkRvZSIsImZpcnN0TmFtZSI6IkpvaG4iLCJlbXBsb3llZVR5cGUiOiJF bXBsb3llZSIsIm5hbWUiOiJKb2huIERvZSIsInJoYXRVVUlEIjoiMTc5YmY0MTYtY2ZhNy0xMWU3LTkxNGUtNTRlZTc1OTMyOTU1IiwicHJlZmVycmVkX3VzZXJuYW1lIjoiamRvZSIsImdpdmVuX25hbWUiOiJKb2huIiwiZmFtaWx5X25hbWUiOiJEb2UiLCJlbWFpbCI6Impkb2VAZXhhbXBsZS5jb20ifQ ==。ZWmsuIRsXeSdE_xefG_o-vYUZR4os_87jgd-7s9BC_-w1bHJ4K3tAIH3r_SxFS1hOYRxO3wsKniePkhcgfyHKDPpvSNc-HLsx3guARDGsdRiqEgszSoJTYvU_XRVcR8FEPPDs0vIov540A9mPPqpH4MPVK-dgZHH5IaSWpceeA91wmL5dh3Z-0nK5wIeFxDw-8PfzSzrF0crTG8Mr9KwaTr9iCTYta13kxIW3WU8xHe6qSYaQEJmKpj4y6YNtwdGvmVn9B9TngSBRliz-4nDj-WcVuWahkppSnuRgEEDsxFZ5DXvnKhK5j1aaU4HSamz7qd2UsgPya7DxpBHHIhcOp0fOzVcDJl4vm_zxnX7cO5Ulm4Vsn-Q5iFMHunXwtNkmxGxQrqWz24CYWF_CxMvcHgjK9pqGeJ6S43v2jQvTPA5dL6dcEhNOd6RH3dD7PJjhXN5b0MP-McjoJXoktnvNRLim_n2Dnsn-t3ceJhJVMqoYPvRd_F51Is1Rcuy3qzNRYtoeiHAkacHIzR5UxPheYtzyo0dtxz9dtHgd-WlWFFL4GyxRb5Ex6153JAZSK4neT4gAXldnSQqqDGHt1XZaeBR4G3l5bffozPuYCR9wDwtkNMI5VK5Q9o81mXdQen0DPt4XZgtSkQOoudNduZFhOy6GIzJAbiNifqJpOyud64 15:22:15.070 [vert.x-eventloop-thread-0] 调试 com.redhat.rhambassador.MainVerticle - 收到的请求: /rest/v1/referrals 15:22:15.072 [vert.x-eventloop-thread-0] 错误 com.redhat.rhambassador.MainVerticle - 使用 3 解析令牌失败 段 java.lang.RuntimeException:段不够或太多 在 io.vertx.ext.jwt.JWT.decode(JWT.java:321) 在 io.vertx.ext.auth.jwt.impl.JWTAuthProviderImpl.authenticate(JWTAuthProviderImpl.java:114) 在 com.redhat.rhambassador.MainVerticle.lambda$buildRoutes$7(MainVerticle.java:197) 在 io.vertx.ext.web.impl.RouteImpl.handleContext(RouteImpl.java:223) 在 io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:101) 在 io.vertx.ext.web.impl.RoutingContextWrapper.next(RoutingContextWrapper.java:149) 在 io.vertx.ext.web.handler.impl.BodyHandlerImpl$BHandler.doEnd(BodyHandlerImpl.java:209) 在 io.vertx.ext.web.handler.impl.BodyHandlerImpl$BHandler.end(BodyHandlerImpl.java:187) 在 io.vertx.ext.web.handler.impl.BodyHandlerImpl.lambda$handle$0(BodyHandlerImpl.java:68) 在 io.vertx.core.http.impl.HttpServerRequestImpl.handleEnd(HttpServerRequestImpl.java:418) 在 io.vertx.core.http.impl.ServerConnection.handleLastHttpContent(ServerConnection.java:475) 在 io.vertx.core.http.impl.ServerConnection.handleContent(ServerConnection.java:469) 在 io.vertx.core.http.impl.ServerConnection.processMessage(ServerConnection.java:449) 在 io.vertx.core.http.impl.ServerConnection.handleMessage(ServerConnection.java:156) 在 io.vertx.core.http.impl.HttpServerImpl$ServerHandlerWithWebSockets.handleMessage(HttpServerImpl.java:705) 在 io.vertx.core.http.impl.HttpServerImpl$ServerHandlerWithWebSockets.handleMessage(HttpServerImpl.java:614) 在 io.vertx.core.net.impl.VertxHandler.lambda$channelRead$1(VertxHandler.java:150) 在 io.vertx.core.impl.ContextImpl.lambda$wrapTask$2(ContextImpl.java:342) 在 io.vertx.core.impl.ContextImpl.executeFromIO(ContextImpl.java:200) 在 io.vertx.core.net.impl.VertxHandler.channelRead(VertxHandler.java:148) 在 io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) 在 io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) 在 io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) 在 io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:310) 在 io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:284) 在 io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) 在 io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) 在 io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:340) 在 io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1359) 在 io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:362) 在 io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:348) 在 io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:935) 在 io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:134) 在 io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:645) 在 io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:580) 在 io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:497) 在 io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:459) 在 io.netty.util.concurrent.SingleThreadEventExecutor$5.run(SingleThreadEventExecutor.java:858) 在 java.lang.Thread.run(Thread.java:748)

【问题讨论】:

你用的是哪个版本的vertx? 我使用的是 3.5.0 【参考方案1】:

尝试使用 vertx 的 jwt 处理程序,它将用户设置到路由上下文并为您进行身份验证

JWTAuth jwtAuth = JWTAuth.create(vertx, new JWTAuthOptions()
        .setPermissionsClaimKey("realm_access/roles")
        .addPubSecKey(new PubSecKeyOptions()
            .setType("RS256")
            .setPublicKey("....your key"));

router.route("/api/rest/a/*").handler(JWTAuthHandler.create(jwtAuth));

【讨论】:

【参考方案2】:

问题在于配置 JSON 不正确,它应该是:

JWTAuth authProvider = JWTAuth.create(vertx, new JWTAuthOptions(new JsonObject()
.put("permissionsClaimKey", "realm_access/roles")
.put("pubSecKeys", new JsonArray()
   .add(new JsonObject()
      .put("publicKey", "...")
      .put("type", "RS256")))));

pubSecKeys 是一个对象数组。为了更安全,您可能不应该使用 JSON 配置,而是使用类型化的配置。

【讨论】:

谢谢,虽然现在我得到“java.lang.RuntimeException: RS256 not supported” RS256 真的不支持算法吗? 该消息正在冒泡,因为提供的密钥无法解码。

以上是关于Vert.x JWT 段数不够或太多的主要内容,如果未能解决你的问题,请参考以下文章

如何在Vert.x REST服务中转发jwt令牌

Vert.x系列(零),开篇,认识Vert.x并创建一个Http服务

Vert.x:Java 中的 Vert.x FTP 客户端是不是有工作示例?

Vert.x初体验

Vert.x 创建HTTP服务-原理篇

Vert.x 入门实战