【问题标题】:Node js JWT to verify token using Google's public keysNode js JWT 使用 Google 的公钥验证令牌
【发布时间】:2019-08-25 02:42:24
【问题描述】:

我正在阅读有关身份验证流程的 https://developers.google.com/actions/identity/google-sign-in 指南。 现在我需要访问用户的个人资料信息,因此我将 JWT 库与代码一起使用:

var decoded = jwt.verify(token, google_key,{algorithms: ['RS256'] });

指南说:

使用适用于您的语言的 JWT 解码库来解码令牌,并使用 Google 的公钥(JWKPEM 格式)来验证令牌的签名。

所以我决定通过使用此代码来使用 PEM 格式:

{
  "6f6781ba71199a658e760aa5aa93e5fc3dc752b5": "-----BEGIN CERTIFICATE-----\nMIIDJjCCAg6gAwIBAgIIPFwAmiva4MkwDQYJKoZIhvcNAQEFBQAwNjE0MDIGA1UE\nAxMrZmVkZXJhdGVkLXNpZ25vbi5zeXN0ZW0uZ3NlcnZpY2VhY2NvdW50LmNvbTAe\nFw0xOTA0MDIxNDQ5MThaFw0xOTA0MTkwMzA0MThaMDYxNDAyBgNVBAMTK2ZlZGVy\nYXRlZC1zaWdub24uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wggEiMA0GCSqG\nSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDUnbzv92s5aD1gmiF71M7tPT+XcQWRc45Y\nQKRflT7sQuEYVx9Ke6D5fuOeThQl7YjLOXFlhLOyyFSBMC9dKQtAJuQ1P2CqKA6Y\nTtfvRQAppqrcivJH/Iz3aSmYF4fTOg1EWv7R/28BOu3cTar2grIpPXo0TLNaq6uT\n3DlyB0QHbs4Xfz1+0Urwf4E63IHWAbOIu9dVjhRNV8Y497xUpO3ZN81at1zjSC30\nvyJbiEIPMyVgJlD7rV0uGP+a4hhcNcN8yofVgr8loLMCjDPO7DrMJYt31xQQCdyi\n0RsSxBQaqGh/soiy5f3pqMZko5YoGS/ME5TOvwRo5ThgYDI6/JUnAgMBAAGjODA2\nMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQMMAoGCCsG\nAQUFBwMCMA0GCSqGSIb3DQEBBQUAA4IBAQC8E4nZ3Sz61gQfOOq3/YpstWrONNol\nH6+L2KyU0+63wG9huxLHJOQ0Xj7oooOjSv4prOE91F3sUjE7P+aVTrwbLpaIpmbd\nloHI6h4yvjWmfdijo8VqSgZyXXhs4USLPEANux870XWEnWXkpR9QeSRQnZuCR2tF\n4nqDN1DMaLv6XCa2q7JPS27tBo9rMxsvk4SQUeSj6qAMyudST1AKDEZkqRdIDUqn\nuaWltHIlky8NUw7gkjOBMIIpIkQapBJ6WDZALebCNsaLbpvTQl3r5ttgW/aSsiXW\nKaJWL3reZU1mVb7JVBoRi8Fks19SnX753fhd4OAdgt91QzVIf7dwY1PG\n-----END CERTIFICATE-----\n",
  "a4313e7fd1e9e2a4ded3b292d2a7f4e519574308": "-----BEGIN CERTIFICATE-----\nMIIDJjCCAg6gAwIBAgIILHP1ZKgNVzIwDQYJKoZIhvcNAQEFBQAwNjE0MDIGA1UE\nAxMrZmVkZXJhdGVkLXNpZ25vbi5zeXN0ZW0uZ3NlcnZpY2VhY2NvdW50LmNvbTAe\nFw0xOTAzMjUxNDQ5MThaFw0xOTA0MTEwMzA0MThaMDYxNDAyBgNVBAMTK2ZlZGVy\nYXRlZC1zaWdub24uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wggEiMA0GCSqG\nSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCU7f9ChF38PxQcCMVx2DT/wY6IvJajhWKL\nLxwMs0Z/xPV5CWqqE9hma8Y4+HIgtZn0Uic5dP0DMfko9946cwTPLhOp8Yu11wCW\n5+oAt7+q6yartJI0hV9LDmI9mPNeTcFePOgU1kt+qyiqF4bN6T6wlXVOLklBDaFE\n9JlCFtr3FWfobxTGvm6BWEdDbk/ocvhpyOG6+lI8QWfu2K8QiFZkQvfkJ6od6V/7\njxYDg8vNFW98UxL6Fbp6uNfu7FP2aPy5PvMaXjX/MF32UyfYJB4/dosN5AWgVotp\nfY1ly1EBISvPof0whdCeAzWmIqdzziGaJ/L5kCw+kFzHDuF4WlhHAgMBAAGjODA2\nMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQMMAoGCCsG\nAQUFBwMCMA0GCSqGSIb3DQEBBQUAA4IBAQCOWDJs2YU7wLenPV0X8Q9LZLX0K+zb\n5HOoKEnf1ZAv4pg9GY0c3DNHfXrknjH+vPM0XbymEK+8EN8/6MBw96U2Lqxxcksj\nCZfK0FnIzT+ROE/FtrHHTnjqcd4aRES5Ffg7EU8lInUhqgmL/q7ZrZ1xBuz1cHPm\nza3aV/gaTs0cjEJWbNkLjDH5j55TBTXxmO32jgsh7i1uTnk1+P0SZKEgXWgKlCmG\nBP0Vx4+IEMfJvy8qdP/yJ50kGwaHjyMNdnxU33zylilxwXPdLWdV9N4KwTuLh4QF\n26EE8nUSCeP9tKKgdKsD/Q/wvuwBGQp4UVx4g/nsZHzxcdONdlhWYlVs\n-----END CERTIFICATE-----\n"
}

但实际上我不知道要从该证书中提取 PUBLIC KEY 以使用我之前所说的 verify() 指令。

(我尝试使用此 Json 变量,但出现错误:)

UnhandledPromiseRejectionWarning: Error: PEM_read_bio_PUBKEY failed

如何从证书中获取公钥?我正在使用 Node.js。 提前致谢。

【问题讨论】:

    标签: node.js jwt google-signin


    【解决方案1】:

    PUBLIC KEY 是实际的字符串:

    "-----BEGIN CERTIFICATE-----\nMIIDJjCCAg6gAwIBAgIIPFwAmiva4MkwDQYJKoZIhvcNAQEFBQAwNjE0MDIGA1UE\nAxMrZmVkZXJhdGVkLXNpZ25vbi5zeXN0ZW0uZ3NlcnZpY2VhY2NvdW50LmNvbTAe\nFw0xOTA0MDIxNDQ5MThaFw0xOTA0MTkwMzA0MThaMDYxNDAyBgNVBAMTK2ZlZGVy\nYXRlZC1zaWdub24uc3lzdGVtLmdzZXJ2aWNlYWNjb3VudC5jb20wggEiMA0GCSqG\nSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDUnbzv92s5aD1gmiF71M7tPT+XcQWRc45Y\nQKRflT7sQuEYVx9Ke6D5fuOeThQl7YjLOXFlhLOyyFSBMC9dKQtAJuQ1P2CqKA6Y\nTtfvRQAppqrcivJH/Iz3aSmYF4fTOg1EWv7R/28BOu3cTar2grIpPXo0TLNaq6uT\n3DlyB0QHbs4Xfz1+0Urwf4E63IHWAbOIu9dVjhRNV8Y497xUpO3ZN81at1zjSC30\nvyJbiEIPMyVgJlD7rV0uGP+a4hhcNcN8yofVgr8loLMCjDPO7DrMJYt31xQQCdyi\n0RsSxBQaqGh/soiy5f3pqMZko5YoGS/ME5TOvwRo5ThgYDI6/JUnAgMBAAGjODA2\nMAwGA1UdEwEB/wQCMAAwDgYDVR0PAQH/BAQDAgeAMBYGA1UdJQEB/wQMMAoGCCsG\nAQUFBwMCMA0GCSqGSIb3DQEBBQUAA4IBAQC8E4nZ3Sz61gQfOOq3/YpstWrONNol\nH6+L2KyU0+63wG9huxLHJOQ0Xj7oooOjSv4prOE91F3sUjE7P+aVTrwbLpaIpmbd\nloHI6h4yvjWmfdijo8VqSgZyXXhs4USLPEANux870XWEnWXkpR9QeSRQnZuCR2tF\n4nqDN1DMaLv6XCa2q7JPS27tBo9rMxsvk4SQUeSj6qAMyudST1AKDEZkqRdIDUqn\nuaWltHIlky8NUw7gkjOBMIIpIkQapBJ6WDZALebCNsaLbpvTQl3r5ttgW/aSsiXW\nKaJWL3reZU1mVb7JVBoRi8Fks19SnX753fhd4OAdgt91QzVIf7dwY1PG\n-----END CERTIFICATE-----\n"
    

    在您的示例中,Google 为我们提供了两个密钥。要知道必须使用哪一个,我们首先需要提取存储在 JWT 标头中的一些信息。为此,我们可以使用相同的 jsonwebtoken 库:

    const header = jwt.decode(YOUR_JWT_HERE, { complete: true }).header;
    /*
    header = {
        alg: 'RS256',
        kid: '6f6781ba71199a658e760aa5aa93e5fc3dc752b5',
        typ: 'JWT'
    }
    */
    

    如您所见,header.kid 匹配从 Google 检索到的证书中的项目。那是您必须用来验证 JWT 的那个。最后,代码如下所示:

    const jwt = require('jsonwebtoken');
    
    const token = YOUR_JWT_VALUE;
    const certificates = {
        "6f6781ba71199a658e760aa5aa93e5fc3dc752b5": "-----BEGIN CERTIFICATE-----\nMIID[...]dwY1PG\n-----END CERTIFICATE-----\n",
        "a4313e7fd1e9e2a4ded3b292d2a7f4e519574308": "-----BEGIN CERTIFICATE-----\nMIID[...]hWYlVs\n-----END CERTIFICATE-----\n",
    };
    
    // Get header information from token
    const header = jwt.decode(token, { complete: true }).header;
    // Get the corresponding public key specified in header
    const cert = certificates[header.kid];
    
    // Verify token
    jwt.verify(token, cert, { algorithms: ['RS256'] }, (err, payload) => {
        if (err) {
          // Not a valid token
          console.log('Error:', err);
          return;
        }
    
        // Token successfully verified
        console.log('Payload:', payload);
    });
    

    注意:Google 的证书会不时更改。为了简单起见,我将它们声明为常量,但您必须牢记这一点。来自Google

    这些键会定期轮换;检查响应中的 Cache-Control 标头以确定何时应再次检索它们。

    来源:

    • 从 JWT here 获取标头信息。
    • 这个guide。向阿德里安·安科纳致敬。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-11-11
      • 2018-01-06
      • 2021-08-14
      • 1970-01-01
      • 2020-01-25
      • 2015-06-27
      • 2015-08-27
      相关资源
      最近更新 更多