使用jose4j生成的令牌在node.js中使用jsonwebtoken验证JWT失败

Nim*_*Nim 1 javascript java node.js json-web-token jose4j

我正在尝试使用node.js中的jsonwebtoken验证jose4j生成的json Web令牌,我看到以下错误:

[错误:PEM_read_bio_PUBKEY失败]

jose4j代码基本上直接取自示例:

RsaJsonWebKey key = RsaJwkGenerator.generateJwk(2048);
key.setKeyId("global.authenticated");

byte[] raw = key.getKey().getEncoded();
Base64.Encoder encoder = Base64.getEncoder();
System.out.printf("Public Key [%s]\n", encoder.encodeToString(raw));

JwtClaims claims = new JwtClaims();
claims.setIssuer("global.gen");
claims.setAudience("global.cons");
claims.setExpirationTimeMinutesInTheFuture(12 * 60);
claims.setGeneratedJwtId();
claims.setIssuedAtToNow();
claims.setNotBeforeMinutesInThePast(2);
claims.setSubject("nim");
claims.setClaim("role", "tester");

JsonWebSignature jws = new JsonWebSignature();
jws.setPayload(claims.toJson());
jws.setKey(key.getPrivateKey());
jws.setKeyIdHeaderValue(key.getKeyId());
jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
String token = jws.getCompactSerialization();
System.out.printf("Generated Token [%s]\n", token);


JwtConsumer jwtConsumer = new JwtConsumerBuilder()
    .setRequireExpirationTime() // the JWT must have an expiration time
    .setAllowedClockSkewInSeconds(30) // allow some leeway in validating time based claims to account for clock skew
    .setRequireSubject() // the JWT must have a subject claim
    .setExpectedIssuer("global.gen") // whom the JWT needs to have been issued by
    .setExpectedAudience("global.cons") // to whom the JWT is intended for
    .setVerificationKey(key.getKey()) // verify the signature with the public key
    .build(); // create the JwtConsumer instance

try {
  //  Validate the JWT and process it to the Claims
  JwtClaims jwtClaims = jwtConsumer.processToClaims(token);
  System.out.println("JWT validation succeeded! " + jwtClaims);
} catch (InvalidJwtException e) {
  // InvalidJwtException will be thrown, if the JWT failed processing or validation in anyway.
  // Hopefully with meaningful explanations(s) about what went wrong.
  System.out.println("Invalid JWT! " + e);
}
Run Code Online (Sandbox Code Playgroud)

因此内部令牌验证正常.但是,当我复制令牌和密钥时(例如下面是来自运行),会报告上述错误:

var jwt        = require('jsonwebtoken'); // used to create, sign, and verify tokens

var key = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkRWAQ0O9LgBoHNAB5m1X8e1sPTzKmBTPCFTSRTzw0AjZozIbN4nIp/3jnQHTbcY0Bf5MDWmtdheSK1a+ew34YcgN2b9Shr+3yZv9PJ97i7gRCqOnI7jbm7PXFBNw1I4aMYc6tV7TKFzvx6008/nYvN3Jey6Z8ItS/FLQRDkV9m/WQkhJpYgvmD6qiwj9d+un+moBQ5/PPgn7Qkg5GyxZUy9PsblUDSrIA0bEiv/wQOXCYUvL9OFzxTUSeIHpdGibhPQVxX3Jnpr293Iq/mOKn3ZO+xBID26m3L8+ik64wte041y1S4HHaE9Q082ai/uBduAwIHcJY5VAHborZYCSaQIDAQAB';
var token = 'eyJraWQiOiJnbG9iYWwuYXV0aGVudGljYXRlZCIsImFsZyI6IlJTMjU2In0.eyJpc3MiOiJnbG9iYWwuZ2VuIiwiYXVkIjoiZ2xvYmFsLmNvbnMiLCJleHAiOjE0NDMwNjMyMDgsImp0aSI6InpweF9ERW8tX1h2Q1hnZmNZTUpiZ0EiLCJpYXQiOjE0NDMwMjAwMDgsIm5iZiI6MTQ0MzAxOTg4OCwic3ViIjoibmltIiwicm9sZSI6InRlc3RlciJ9.inEebSQ8jYPQsTpHnvw-gMpoNbJl5ErUkS8FtkDagWrwijUgG8XYYP8FLi2ZCpdgDqUsP6nE1iG0_2wWuL7B7C7wUpZlrqR2bEOG2cXK9s26VqNAXu8I7BTDaZBKmdOt1aFVWozGsN8iUCsQ7Yt9-GfvNRP1yeOoMgpOxf_wVa0QVzsV18aVi_oSeiMqOkQ_6n7JOjFVdiURm0ew4vh5TBaMcEcS35a9jtPxuFR_Z_FaLUk0g06PDVKcdsK1-FYRAGBlRGDkea8Hs9Zh-ZIxgcs2QfWzq5PSsIKum1dWqNLW04ullWmlbAO-5d0V0NAnkh4FFoi3N7AedvkILJgbqA';

jwt.verify(token, key, { algorithms: ['RS256'] }, function(err, decoded) {
  if (err)
    console.log(err);
  else
    console.log(decoded);
});
Run Code Online (Sandbox Code Playgroud)

我缺少一些魔法(jose4j或jsonwebtoken),这将允许生成的令牌由公钥验证?

在旁注中,将令牌粘贴到jwt.io中会正确解码标头和有效负载,但是签名无法使用相同的公钥进行验证.我猜这个问题确实存在于jose4j方面 - 但不确定.

Nim*_*Nim 5

我会添加这个作为答案,因为某人会遇到类似的东西.问题源于传入jsonwebtoken的密钥格式.它不能只是一个纯文本公钥,它必须具体遵循PEM格式.因此,一旦我将密钥转换为PEM文件,特别是通过进行以下更改:

byte[] raw = key.getKey().getEncoded();
Base64.Encoder encoder = Base64.getMimeEncoder(64, new byte[]{'\n'});
Run Code Online (Sandbox Code Playgroud)

然后包装

-----BEGIN PUBLIC KEY-----
<Key>
-----END PUBLIC KEY-----
Run Code Online (Sandbox Code Playgroud)

然后将生成的文件传递给jsonwebtoken,可以继续进行身份验证.我没有意识到传入验证步骤的证书应该严格格式化(即使用行大小和包装器!)

注意:bouncycastle包有一个PemObject类和一个PemWriter应该使编写文件更容易 - 但我不想为此拉入另一个包.也许jose4j的维护者可以为他们的包添加一个小类.

  • jose4j v0.5.0最近发布了,它有`KeyPairUtil.pemEncode(PublicKey publicKey)`以及`fromPemEncoded(String pem)`,它有助于将PublicKey对象转换为PEM编码密钥. (2认同)