【问题标题】:JWT validation failed: BAD_SIGNATUREJWT 验证失败:BAD_SIGNATURE
【发布时间】:2018-12-03 01:12:47
【问题描述】:

我使用以下文件遇到问题

https://github.com/GoogleCloudPlatform/java-docs-samples/blob/master/appengine-java8/appidentity/src/main/java/com/example/appengine/appidentity/SignForAppServlet.java

使用应用引擎默认服务帐户编写方法测试以生成签名的 JWT

private String test() throws CertificateException, UnsupportedEncodingException, 
    NoSuchAlgorithmException, InvalidKeyException, SignatureException {

           long now = System.currentTimeMillis() / 1000;

           JSONObject headerJson = new JSONObject();
           headerJson.put("typ", "JWT");
           headerJson.put("alg", "RS256");

           JSONObject payloadJson = new JSONObject();
           payloadJson.put("iat", now);
           payloadJson.put("exp", now + 3600);
           payloadJson.put("iss", "{test-project}@appspot.gserviceaccount.com");
           payloadJson.put("sub", "{test-project}@appspot.gserviceaccount.com");
           payloadJson.put("aud", "https://echo-api.endpoints.{test-project}.cloud.goog");

          String headerAndPayload = String.format("%s.%s", Base64.getUrlEncoder().encodeToString(headerJson.toString().getBytes()), Base64.getUrlEncoder().encodeToString(payloadJson.toString().getBytes()));

          AppIdentityService appIdentityService = AppIdentityServiceFactory.getAppIdentityService();
          AppIdentityService.SigningResult signingResult = appIdentityService.signForApp(headerAndPayload.getBytes());

          String signedJwt = String.format("%s.%s", headerAndPayload , new 
          String(Base64.getUrlEncoder().encode(signingResult.getSignature())));

          return signedJwt;
}

我需要生成签名的 JWT 来验证在应用引擎中运行的 java 后端。使用开放 API 云端点保护 API。以下是我的 openapi.yaml

  swagger: "2.0"
       info:
               description: "A simple Google Cloud Endpoints API example."
       title: "Endpoints Example"
       version: "1.0.0"
       host: "echo-api.endpoints.{test-project}.cloud.goog"

consumes:
            - "application/json"
produces:
            - "application/json"
schemes:
          - "https"

 paths:
         "/test/echo":
          post:
                description: "Echo back a given message."
                operationId: "echo"
          produces:
                  - "application/json"
          responses:
                  200:
          description: "Echo"
          schema:
                   $ref: "#/definitions/echoMessage"
          parameters:
           -
                   description: "Message to echo"
                   in: body
                   name: message
                   required: true
                   schema:
                           $ref: "#/definitions/echoMessage"
                   security:
                          - api_key: []
                            google_jwt: []

       definitions:
                  echoMessage:
                        type: "object"
                        properties:
                        message:
                        type: "string"

       securityDefinitions:
              google_jwt:
              authorizationUrl: ""
              flow: "implicit"
              type: "oauth2"
              x-google-issuer: "stl-cardio-dev@appspot.gserviceaccount.com"
              x-google-jwks_uri: "https://www.googleapis.com/service_accounts/v1/jwk/{test-project}@appspot.gserviceaccount.com"

创建 JWT 后,我尝试访问 /test/echo 它给出“JWT 验证失败:BAD_SIGNATURE”。

我尝试了

中描述的python客户端

https://github.com/GoogleCloudPlatform/python-docs-samples/blob/master/endpoints/getting-started/clients/service_to_service_gae_default/main.py

我使用以下“标头和有效负载”和“签名方法”,收到以下结果。

(01)。 python header_and_payload + python app_identity.sign_blob 方法 => 成功

(02)。 python header_and_payload + java appIdentity.signForApp() => 错误

(03)。 java headerAndPayload + python app_identity.sign_blob 方法 => 成功

(04)。 java headerAndPayload + java appIdentity.signForApp() => 错误

我看到 appIdentity.signForApp() 中的问题导致我的 java 实现。

我找不到完整的示例或文档。我如何使用 java 生成正确的签名 JWT。

谢谢。

【问题讨论】:

  • 在 Base64 编码时,您是否尝试过使用 utf-8 字符集调用 getBytes?
  • 我试过了。字符串 headerAndPayload = String.format("%s.%s", Base64.getUrlEncoder().encodeToString(headerJson.toString().getBytes(UTF-8)), Base64.getUrlEncoder().encodeToString(payloadJson.toString() .getBytes(UTF-8)));但结果是一样的。
  • 按照Troubleshooting JWT Validation 的步骤来确定签名的 JWT 或您的 openapi.yaml 是否存在问题。缩小问题范围并告诉我,以便我们继续解决问题。
  • 我遵循这个,我可以确认签名 JWT 中的问题。也 python 代理完美地与相同的 openapi.yaml 一起工作。文档说签名结果的“signingResult.getSignature()”是“SHA256withRSA”散列。我们需要将此散列字节数组转换为“Base64 url​​ 安全编码”以生成最终的 JWT。我看到那里有问题。 SHA256withRSA -> Base64 或 SHA256withRSA -> 需要字符串。
  • 尝试使用 this example 创建签名的 JWT

标签: java google-app-engine jwt google-cloud-endpoints google-cloud-endpoints-v2


【解决方案1】:

如果没有错,您正在寻找 JWT 的 Java 实现。

生成和验证 JWT 令牌的最低要求是 AlgorithmSecret key

我正在使用 JWT 的 Java 实现

<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.0</version>
</dependency>

类文件

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;


...


    public String generateToken(String username) {
        String audience = generateAudience();
        return Jwts.builder()
                .setIssuer( APP_NAME )
                .setSubject(username)
                .setAudience(audience)
                .setIssuedAt(timeProvider.now())
                .setExpiration(generateExpirationDate())
                .signWith( SIGNATURE_ALGORITHM, SECRET )
                .compact();
    }



    private Claims getAllClaimsFromToken(String token) {
        Claims claims;
        try {
            claims = Jwts.parser()
                    .setSigningKey(SECRET)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            LOGGER.error("Could not get all claims Token from passed token");
            claims = null;
        }
        return claims;
    }

这里 generateToken 将获取所有声明详细信息以及密钥和算法。

getAllClaimsFromToken 用于从令牌中读取详细信息。它基本上验证了 Token。 如果有任何错误将相应地抛出异常

我为此写了answer。这是工作代码。您可以参考 TokenHelper.java 以获取更多详细信息

【讨论】:

  • 感谢您的回复。在此之前我使用了自己的 JWT 实现。这是完美的工作。现在我将后端移至谷歌应用引擎,我需要使用应用引擎服务帐户和谷歌云端点进行身份验证。标头和有效负载部分也是正确的,签名部分有问题。我需要使用 AppIdentityService 来完成。
猜你喜欢
  • 2017-09-21
  • 2022-01-14
  • 1970-01-01
  • 2016-06-12
  • 2018-04-30
  • 2018-08-06
相关资源
最近更新 更多