从 djwt 1.6 版开始支持RS256。
但是,这里我使用了一个名为God Crypto的加密模块来验证 RS256 签名令牌。God Crypto 具有解析JSON Web Key (JWK) 的功能,这是我们需要验证 Google 提供的 JWT 的功能。
首先,我展示了一个简短的示例,其中包含 JWK 的硬编码值和我为本演示制作的令牌:
import { RSA, encode } from "https://deno.land/x/god_crypto@v1.4.8/mod.ts";
const jwt = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlctNjduZWt0WVRjOEpWWVBlV0g1c1dlN1JZVm5uMFN5NzQxZjhUT0pfQWMifQ.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.hiKxeC66LIyVKOXjiOk7iScFPy_5-ATw7hEfqGij8sBZmwXAeTPT5BRFYHitFKSXomGqmy_63LLvg4zbhcTTmNf8XIeDAuLsC32soO5woSByisswWHVf8BgxMkI_FPW_oEtEQ8Xv3FL_1rF9j9Oy3jIjgjqhFhXUtsSQWAeuGYH-OQljFwiuO5Bqexcw-H71OEWvQLQof_6KJ0viJyte8QEwEVridyO834-ppHzeaoW2sTvZ22ZNfxPCew0Ul2V_TxHTtO7ZuJCZ81EmeIV6dYJ2GrYh3UN1x1PHy4-tEn-PL4otlaO3PYOcXfCHxHa6xtPsquzPZJnB1Vq8zULLfQ"
// public key in JSON Web Key(JWK) format:
const pubJWK = {
"kty": "RSA",
"e": "AQAB",
"use": "sig",
"kid": "W-67nektYTc8JVYPeWH5sWe7RYVnn0Sy741f8TOJ_Ac",
"alg": "RS256",
"n": "kFpGoVmBmmKepvBQiwq3hU9lIAuGsAPda4AVk712d3Z_QoS-5veGp4yltnyEFYyX867GOKDpbH7OF2uIjDg4-FPZwbuhiMscbkZzh25SQmfRtCT5ocUloQiopBcNAE-sd1p-ayUJWjhPrFoBrBLZHYxVEjY4JrWevQDj7kSeX7eJpud_VuZ77TNoIzj7d_iUuJUUlqF1ZF540igHKoVJJ6ujQLHh4ob8_izUuxX2iDq4h0VN3-uer59GsWw6OHgkOt85TsjMwYbeN9iw_7cNfLEYpSiH-sVHBCyKYQw7f8bKaChLxDRhUUTIEUUjGT9Ub_A3gOXq9TIi8BmbzrzVKQ"
}
// parse the JWK to RSA Key
const publicKey = RSA.parseKey(pubJWK)
const rsa = new RSA(publicKey)
// split the token into it's parts for verifcation
const [headerb64, payloadb64, signatureb64] = jwt.split(".")
// verify the signature based on the given public key
console.log(await rsa.verify(
encode.base64url(signatureb64),
headerb64 + "." + payloadb64,
{ algorithm: "rsassa-pkcs1-v1_5", hash: "sha256" },
))
可以直接运行上面的代码,得到结果
真的
为成功验证。
第二个示例从 google certs 端点加载 JWKS(JSON Web 密钥集),尝试找到匹配的密钥,然后在找到匹配的密钥时验证令牌。
令牌标头包含一个密钥 ID(“kid”),它标识应该用于验证的密钥。
{
"alg": "RS256",
"typ": "JWT",
"kid": "W-67nektYTc8JVYPeWH5sWe7RYVnn0Sy741f8TOJ_Ac"
}
import { RSA, encode } from "https://deno.land/x/god_crypto@v1.4.8/mod.ts";
import { decode } from "https://deno.land/x/djwt@v2.2/mod.ts"
// the JWT that we want to verify
const jwt = "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IlctNjduZWt0WVRjOEpWWVBlV0g1c1dlN1JZVm5uMFN5NzQxZjhUT0pfQWMifQ.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.hiKxeC66LIyVKOXjiOk7iScFPy_5-ATw7hEfqGij8sBZmwXAeTPT5BRFYHitFKSXomGqmy_63LLvg4zbhcTTmNf8XIeDAuLsC32soO5woSByisswWHVf8BgxMkI_FPW_oEtEQ8Xv3FL_1rF9j9Oy3jIjgjqhFhXUtsSQWAeuGYH-OQljFwiuO5Bqexcw-H71OEWvQLQof_6KJ0viJyte8QEwEVridyO834-ppHzeaoW2sTvZ22ZNfxPCew0Ul2V_TxHTtO7ZuJCZ81EmeIV6dYJ2GrYh3UN1x1PHy4-tEn-PL4otlaO3PYOcXfCHxHa6xtPsquzPZJnB1Vq8zULLfQ"
// get the JSON Web Key Set (JWKS) from google certs endpoint
const certs = fetch("https://www.googleapis.com/oauth2/v3/certs");
var jwks = await certs.then((response) => {
return response.json()
})
// decode the JWT to get the key Id ('kid') from the header
// in Version 2.2 of djwt decode returns a 3 tuple instead of an object
const [ header, payload, signature ] = decode(jwt)
var keyId = Object(header).kid
// find the matching JSON Web Key (JWK)
var pubjwk = findJWKByKeyId(String(keyId))
// parse the JWK to RSA Key
if (pubjwk) {
const publicKey = RSA.parseKey(pubjwk)
const rsa = new RSA(publicKey)
// split the token into it's parts for verifcation
const [headerb64, payloadb64, signatureb64] = jwt.split(".")
// verify the signature based on the given public key
console.log(await rsa.verify(
encode.base64url(signatureb64),
headerb64 + "." + payloadb64,
{ algorithm: "rsassa-pkcs1-v1_5", hash: "sha256" },
))
}
else
{
console.log("key with kid (" + keyId +") not found")
}
// function to find a certain JWK by its Key Id (kid)
function findJWKByKeyId(kid:string) {
return jwks.keys.find(
function(x:string){ return Object(x).kid == kid }
)
}
正如 Scott Brady解释的那样,在您看到的令牌标头"alg": "RS256"
中rsa.verify()
,algorithm: "rsassa-pkcs1-v1_5"
使用了 in,这是 RS256` 的长格式。RS
由于给定的令牌(在jwt.io上创建的示例)未由 Google 签名,因此找不到匹配的密钥,因此无法对其进行验证。使用您自己的 Google 签名的 JWT 来测试上述代码。
部分验证码基于God Crypto Github页面中的示例