我正在尝试使用Google和OpenID Connect实现联合登录系统,并且我无法验证和解析我从Google收到的JWT ID令牌.我在这里关注Google的文档.
根据文档的建议,我正在尝试使用现有的JWT库.GitHub上最流行的PHP版本似乎是PHP_JWT.问题似乎是JWK键的格式.
上面链接的谷歌文档说,从jwks_uri
他们的发现文档中显示的端点获取密钥.该端点返回以下内容:
{ "keys": [ { "kty": "RSA", "alg": "RS256", "use": "sig", "kid": "1771931eb0eb64eb97733e857685be153e079bb9", "n": "AMNFQMNJw/EVwrYsyPTnEHWkaPinPb4ngc/SqD701aisFhbU9/wWoKADeFtwfBcWl1qjzIqhPorQElB+2mtiqUh3Qtaazt1x5wA9XnJDe6kjtMGm9nNLMilSVNBilAE8GIdbciMycISfOfL0WRaJrqpNxewNEVZjuYiGzOWahiDP", "e": "AQAB" }, { "kty": "RSA", "alg": "RS256", "use": "sig", "kid": "7b3bc600209875d3c42ae277a0d018d1d21986ec", "n": "AN2UvG5+hNEMIPIbnpPm+JQi6LFWXBPzg3Ltb3xkVmSTjVaCFWppw/ZYRBgpToGKZP9XJstlOE88SDUFSMZIkIqtLpnUqmZax2Zc2gjEB9PhmHSH3/tTmtZ1U0X6V+crqitZ2uc3NV78vCn9/s+WuPwk/gfKBG8Cirb0fgLmsPd9", "e": "AQAB" } ] }
查看JWT类和方法的源代码,看起来参数可以是一个数组,但是它们希望数组键是和数组值:.它很简单,可以拉出属性并将它们用作数组键,但应该用什么作为数组值?decode
verify
$keys
kid
@param string|resource $key for HS*, a string key works. for RS*, must be a resource of an openssl public key
kid
从谷歌的JWKs文档来看,它看起来像我们正在使用RS*
,但我不知道关键对象的哪一部分resource of an openssl public key
.我已经尝试使用整个stdClass对象而只是n
字符串,但两者都失败了openssl_verify
.该函数发出通知说:"警告:openssl_verify():提供的密钥参数不能被强制转换为公钥".
所以,显然,我传递的是错误的密钥,但是正确的密钥是什么?
谷歌的库似乎使用不同的端点来获取密钥.该端点似乎返回了一系列证书.我需要使用类似的东西吗?如果是这样,为什么文档会告诉您使用jwks_uri
端点?
两个端点包含相同的信息,但格式不同.
该jwks_uri
端点给你的模量和指数 RSA公钥的价值.您可以使用这两个值来生成你的PEM文件https://www.googleapis.com/oauth2/v1/certs.
对于将来尝试这样做的人,我想提供一个完整的答案;
JSON密钥中的n
和e
部分jwks_uri
给出模数和指数,可用于检索公钥(这是验证签名所需的全部内容).在这篇文章中详细介绍了如何在纯PHP中完成此操作:
openssl:我如何从模数中获取公钥
但是,您应该知道Google提供的JSON文档jwks_uri
使用URL安全base64编码(即替换了+和/字符的普通base64).如果不考虑这一点,可能仍然会给您一个无效的证书.既然你提到使用php-jwt
,使用phpseclib从模数和指数获取公钥的工作代码是:
$modulus = 'someencodedmodulusvalue'; $exponent = 'someencodedexponentvalue'; $rsa = new Crypt_RSA(); $modulus = new Math_BigInteger(JWT::urlsafeB64Decode($modulus), 256); $exponent = new Math_BigInteger(JWT::urlsafeB64Decode($exponent), 256); $rsa->loadKey(array('n' => $modulus, 'e' => $exponent)); $rsa->setPublicKey(); $pubKey = $rsa->getPublicKey();