【问题标题】:How to verify JWT signature using a token and public key in Java如何在 Java 中使用令牌和公钥验证 JWT 签名
【发布时间】:2018-01-06 23:20:11
【问题描述】:

我有一个字符串形式的令牌,我下载了公共证书并从中创建了一个公钥,如下所示。

但我不确定如何使用这么多信息进行验证。

我找到了适用于 C# 和 .NET 的解决方案,但没有找到适用于 Java 的解决方案。 请注意,我没有 jks 文件或私钥。

    FileInputStream fin = new FileInputStream("d://public.crt");
    CertificateFactory f = CertificateFactory.getInstance("X.509");
    X509Certificate certificate = (X509Certificate)f.generateCertificate(fin);
    PublicKey pk = certificate.getPublicKey();

【问题讨论】:

    标签: java jwt


    【解决方案1】:

    如果您询问 JSON WebToken,您可以按照以下代码示例进行操作:

    import javax.xml.bind.DatatypeConverter;
    import io.jsonwebtoken.Jwts;
    import io.jsonwebtoken.Claims;
    
    //Sample method to validate and read the JWT
    private void parseJWT(String jwt) {
    
        //This line will throw an exception if it is not a signed JWS (as expected)
        Claims claims = Jwts.parser()         
           .setSigningKey(DatatypeConverter.parseBase64Binary(apiKey.getSecret()))
           .parseClaimsJws(jwt).getBody();
        System.out.println("ID: " + claims.getId());
        System.out.println("Subject: " + claims.getSubject());
        System.out.println("Issuer: " + claims.getIssuer());
        System.out.println("Expiration: " + claims.getExpiration());
    }
    

    更多阅读,可以访问点击here

    【讨论】:

    • 什么是 apiKey 对象,鉴于我只有一个公钥证书文件,我如何获取它的秘密。
    • apiKey 是 com.stormpath.sdk.api.ApiKey 的对象,用于存放 apikey。字符串路径 = "资源/.stormpath/apiKey.properties"; ApiKey apiKey = ApiKeys.builder().setFileLocation(path).build();
    • 这不是回答用户的问题。使用密钥验证是使用 HS256 (hmac),而使用公钥验证是 RS256。
    【解决方案2】:

    使用 Auth0 库 (com.auth0:java-jwt) 在 Java 中验证 JWT:

    1. 检索已签署密钥的算法,例如:

      // Load your public key from a file
      final PublicKey ecdsa256PublicKey = getPublicKey(...);
      final Algorithm algorithm = Algorithm.ECDSA256((ECPublicKey) ecdsa256PublicKey, null);
      
    2. 使用相应的算法验证其签名:

      final DecodedJWT decodedJWT = JWT.decode("J.W.T[...]");
      // Will throw a SignatureVerificationException if the token's signature is invalid
      algorithm.verify(decodedJWT);
      

    【讨论】:

      【解决方案3】:

      我做了这样的事情来验证 JWT

      try {
              DecodedJWT decodedJWT = JWT.decode(jwt); // your string
              JwkProvider provider =  new JwkProviderBuilder(new URL("JWKS URL")).build();
              Jwk jwk = provider.get(decodedJWT.getKeyId());
              Algorithm algorithm = Algorithm.RSA256((RSAPublicKey) jwk.getPublicKey(), null);
      
              Verification verifier = JWT.require(algorithm);
              verifier.build().verify(decodedJWT);
          } catch (JWTVerificationException | JwkException | MalformedURLException e) {
              // throw your exception
          }
      

      JwkProviderBuilder 可能很昂贵,因此如果您使用的是 Spring,您可以将其提取为另一种方法并使用 @PostConstruct 进行注释以进行优化。

      【讨论】:

      • 我已经试过了,程序在 "provider.get(decodedJWT.getKeyId())" 行
      • 您遇到的错误是什么?您确定您传递的 JWT 或 JWKs URL 正确吗?
      【解决方案4】:

      使用 RSA 密钥的工作示例如下所示:

      /* Verification of JWT */
      try {
          String token = "some-token";
          String publicKey = "some-key";
          
          //Convert public key string to RSAPublicKey
          byte[] publicKeyByteArr = Base64.getDecoder().decode(publicKey);
          KeyFactory keyFactory = KeyFactory.getInstance("RSA");
          RSAPublicKey rsaPublicKey = (RSAPublicKey) keyFactory.generatePublic(new X509EncodedKeySpec(publicKeyByteArr));
      
          //If the token has an invalid signature, JWTVerificationException will raise.
          Algorithm algorithm = Algorithm.RSA256(rsaPublicKey, null);
          JWTVerifier verifier = JWT.require(algorithm)
                      //.withIssuer("auth0")
                      .build(); //Reusable verifier instance
          DecodedJWT jwt = verifier.verify(token);
      
      }catch(InvalidKeySpecException | NoSuchAlgorithmException | JWTVerificationException e) {
          logger.info("JWT verification is failed");
          throw new ResponseStatusException(HttpStatus.UNAUTHORIZED);
      }
      

      很明显,但请注意,token 和 publicKey 是任意的。

      【讨论】:

        猜你喜欢
        • 2020-01-25
        • 1970-01-01
        • 2021-11-16
        • 1970-01-01
        • 2019-11-01
        • 2016-04-17
        • 2017-11-22
        • 2019-08-25
        • 2020-12-27
        相关资源
        最近更新 更多