如何使用 RSA256 算法生成 JWT 签名?

Posted

技术标签:

【中文标题】如何使用 RSA256 算法生成 JWT 签名?【英文标题】:How to generate JWT-Signature using RSA256 algorithm? 【发布时间】:2018-12-27 06:03:48 【问题描述】:

我有一个PrivateKey 和一个PublicKey 并使用privateKey 来初始化SignaturepublicKey 来验证Signature

KeyFactory keyFactory = KeyFactory.getInstance("RSA"); 

// decode public key
X509EncodedKeySpec publicSpec = new X509EncodedKeySpec(pubKeyBytes);
RSAPublicKey pubKey = (RSAPublicKey) 
keyFactory.generatePublic(publicSpec);

//decode private key
PKCS8EncodedKeySpec privSpec = new PKCS8EncodedKeySpec(prvKeyBytes);
RSAPrivateKey privKey = (RSAPrivateKey) 
keyFactory.generatePrivate(privSpec);

//header and body Base64 decoded value
String headerString = mapper.writeValueAsString(header);
String headerEncoded = 
Base64.getUrlEncoder().encodeToString(headerString.getBytes());
String payloadString = mapper.writeValueAsString(payload);
String payloadEncoded = 
Base64.getUrlEncoder().encodeToString(payloadString.getBytes());
String tempAccessToken = hearderEncoded+"."+payloadString;

Signature sign = Signature.getInstance("SHA256withRSA");
sign.initSign(privKey);
sign.update(tempAccessToken.getBytes("UTF-8"));
byte[] signatureBytes = sign.sign();
sign.initVerify(pubKey);
sign.update(tempAccessToken.getBytes("UTF-8"));     

String jsonToken = Base64.getUrlEncoder().encodeToString(signatureBytes);
String JWTtoken = tempAccessToken + "." + jsonToken; 

最后我得到了下面的 JWT 令牌(虚拟值):

eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiI4MzliN2NhNC02MDE1LTQ0OWQtOGZiNi02jkyYzk1Ny1jYTNjLTQyMWQtOTk2zY2VkNTAzZGViNWYiLCJleHAiOjE1MzIwMDQwMTcsImF1ZCI6ImFjY291bnQtZC5kb2N1c2lnbi5jb20iLzY29wZSI6InNpZ25hdHVyZSBpbXBlcnNvbmF0aW9uIn0 = .YNZzR0HgPWFm4dXMMHn3czEDRukYUB0Hyw7YP_BGY2dniIMqpH4Ctz5EEHcHrNT_mGImcp026w-isYgv56TTugYnkcAs8HH0YXa1Ey0skdjVYoZHdeyPC8Ci9xeOQF9wf4VjrBboaRxWkVXfngOHHewpV42NcaXxwmGlresWukHVmmjbFokd1Cm5BJKVhVlsZWuftcJlC3XoO9REjaZX78YTY9S5bpXmsZBYr20wHsWJrkP9EWGf7WSGHVXGBJfCpvOTZDC8_4B12ToD_RKjk6n5s8-F7X54KY4kx6Gg7xnk55vDw == P>

我无法使用此 JWT 令牌获取 accessToken。我会收到回复:

“错误”:“无效请求”;

注意:我正在使用此 JWT 令牌来获取 DocuSign 应用程序的访问令牌。

【问题讨论】:

令牌无效。您应该在问题中包含正在构建tempAccessToken 的代码。问题肯定是你正在编码base64,它应该是base64url 我已经添加了用于获取 tempAccessToken 的代码。 您的令牌不是 base64url 编码的。查看base64url 方法。您是否在问题中包含了与代码对应的令牌?好像没有更新 DocuSign link 我已经获得了标头和有效负载 Base64 编码值并添加“。”根据文档的值之间。 不,它说的是 base64 url​​ 编码 rs256sign(<base64URL-encoded header>.<base64URL-encoded body>) 。 JWT 部分必须以 base64url 编码。见RFC7519 【参考方案1】:
/* Header */
$header = json_encode(['typ' => 'JWT', 'alg' => 'sha256']);

/* Payload */
$payload = json_encode(['logged_in_id' => 1, 'logged_in_name' => 'Test', 'logged_in_username' => 'test']);

// Encode Header to Base64Url String
$base64UrlHeader = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($header));

// Encode Payload to Base64Url String
$base64UrlPayload = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($payload));

// Create Signature Hash
$signature = hash_hmac('sha256', $base64UrlHeader . "." . $base64UrlPayload, SECRET, true);

// Encode Signature to Base64Url String
$base64UrlSignature = str_replace(['+', '/', '='], ['-', '_', ''], base64_encode($signature));

// Create JWT
$jwt = $base64UrlHeader . "." . $base64UrlPayload . "." . $base64UrlSignature;

这是创建 JWT 的完整代码。在上面的 SECRET 中,您需要在任何地方使用将用于生成 JWT 的密钥定义该常量。

此代码是生成 JWT 的核心代码,但您也可以使用任何使您的任务变得简单的库,因为您不需要编写完整的代码,您只需要包含该库并调用函数并通过仅需要的参数。

您可以下载库here

【讨论】:

我只获得了正确格式的所有 base64Url 值。我的问题是签名。在 JWT.io 中使用令牌时,它显示未经验证。 使用上面的代码,它会像魅力一样工作,在 jwt.io 中使用它不会显示未经验证。 我没有得到 str_replace 和 base64_encode 方法。 它是生成 JWT 的规则,为了让我们的令牌在 jwt.io 上得到验证,我们需要遵循它们遵循的规则。 @AkshitAhuja,你的回答没有意义。 OP 要求提供 Java 代码,但您提供了 php。它是必需的非对称 RSA 密钥,但您的代码使用的是 HMAC。标题中包含的算法sha256不正确,应该是HS256,但是OP要求RS256

以上是关于如何使用 RSA256 算法生成 JWT 签名?的主要内容,如果未能解决你的问题,请参考以下文章

Jwt介绍

如何使用 System.IdentityModel.Tokens.Jwt 生成具有 Google OAuth2 兼容算法 RSA SHA-256 的 JWT?

JWT 签名算法 HS256 与 RS256

如何使用 sha512 为 JWT 生成 RSA 密钥?

如何使用 RSA512 算法创建签名的 JWT

Python JWT 库 PyJWT 使用 HS256 签名时遇到问题 - 使用 SHA-256 哈希算法的 HMAC