我一直在研究这个问题太久了。我正在寻找一个截至2016年9月的工作示例,用于验证Google idToken,例如
eyJhbGciOiJSUzI1NiIsImtpZCI6IjZjNzgxOTQyZDg0OWJhMmVjZGE4Y2VkYjcyZDM0MzU3ZmM5NWIzMjcifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhdWQiOiIxMDQ5MTQ4MTU2NTQ2LTk2YjFxcTJsNTJtODVtODB0ZHVoZHVma2RwODRtN2tuLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwic3ViIjoiMTEyNTk4NDgzNjQ2MjY1OTYxNTQwIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImF6cCI6IjEwNDkxNDgxNTY1NDYtdjJwZjRlbGhzOGNwcXBlcWZkMzU5am5nOWs5aW5kcTQuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJlbWFpbCI6InRlc3R1c2VydGh4QGdtYWlsLmNvbSIsImlhdCI6MTQ3NDc1NDMzMiwiZXhwIjoxNDc0NzU3OTMyLCJuYW1lIjoiVGVzdCBVc2VyIiwicGljdHVyZSI6Imh0dHBzOi8vbGg0Lmdvb2dsZXVzZXJjb250ZW50LmNvbS8tU0dldkZZRDlaWFEvQUFBQUFBQUFBQUkvQUFBQUFBQUFBQUEvQVBhWEhoUmtuX1hEaEhNLTEzeVMwTUtBcFNrZG1zVEdYdy9zOTYtYy9waG90by5qcGciLCJnaXZlbl9uYW1lIjoiVGVzdCIsImZhbWlseV9uYW1lIjoiVXNlciIsImxvY2FsZSI6ImVuIn0.btukbBvhek6w14CrBVTGs8X9_IXIHZKpV1NzJ3OgbGUfmoRMirNGzZiFAgrR7COTeDJTamxRzojxxmXx6EEkQqNQcbyN8dO0PTuNt9pujQjLbFw_HBhIFJQaJSR3-tYPN-UtHGQ5JAAySsvCPapXbxyiKzTyvGYRSU65LmyNuiGxe6RQe1zHjq2ABJ4IPRqKPuFupnGRPWYyBSTPU7XQvtfhgyqA0BWZUfmCIFyDxQhvMaXNLTs01gnGVhcUDWZLi9vuUiKUlz3-aSSbwdfCMAljhBHnjpYO6341k5-qmgKkWawv8DX_nMEzntsCMCr664rP4wFEbsRB5ledM9Pc9Q
使用Google推荐的方式并提取" accounts.google.com/.well-known/openid-configuration"对于jwks_uri并拉动" www.googleapis.com/oauth2/v3/certs" ;,产生相关条目
{ "kty": "RSA", "alg": "RS256", "use": "sig", "kid": "6c781942d849ba2ecda8cedb72d34357fc95b327", "n": "s1dt5wFFaYl-Bt7Yb7QgWEatLJfxwWDhbd5yvm2Z4d1PRgNVQa9kwOArQNoOJ-b-oZnXLVFsVASUXEAumGf1ip5TVCQmMBKqlchSDNuoZfoWdpCCX7jx4gNuS43pS6VqV3QDjWnoXRTHaUi5pZEbpAmWpOeG_CfmewNVwBXPFx8-mtvEdtxIrspX4ayXTViR4vHc7MhQhUxllFbocxMjJysDQuZV9wN3MI0lVtQdf52SKJwF3lhvWA9-WAEZ1q8wq-I93Sfte95RaFjDqCH--Sh-8DjhK4OvgItcEGd5QRHjdLvrayPwaDQbpMRN2n3BkVWIxKJubtRiSeWbawCklQ", "e": "AQAB" }
如果我将令牌传递给https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=TOKEN,就会进行验证,但这不是一个真正的答案,因为他们不会经常改变这种情况,但每次进行额外的网络通话只是在寻找麻烦。< / p>
那么有人能指出一个有效的例子吗?我已经尝试过phpseclib,但它从未验证过。我此时可能已经找了大约40个小时,而且我在我的智慧&#39;端。
感谢任何帮助。
我的相关代码:
$modulus = "";
$exponent = "";
$token = $_POST['token'];
$pieces = explode(".", $token);
$header = json_decode(base64_decode(str_replace(['-','_'], ['+','/'], $pieces[0])), true);
$alg = $header['alg'];
$kid = $header['kid'];
$payload = base64_decode(str_replace(['-','_'], ['+','/'], $pieces[1]));
$signature = str_replace(['-','_'], ['+','/'], $pieces[2]);
//$signature = base64_decode(str_replace(['-','_'], ['+','/'], $pieces[2]));
if (testGoogleList($alg, $kid, $modulus, $exponent))
{
echo "Found in list: kid=".$kid."\n";
echo "n: (base64URL)".$modulus."\n";
echo "e: (base64URL)".$exponent."\n";
$modulus = str_replace(['-','_'], ['+','/'], $modulus);
$exponent = str_replace(['-','_'], ['+','/'], $exponent);
echo "n: (base64)".$modulus."\n";
echo "e: (base64)".$exponent."\n";
$rsa = new Crypt_RSA();
$rsa->setHash("sha256");
$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
$modulus = new Math_BigInteger($modulus, 256);
$exponent = new Math_BigInteger($exponent, 256);
echo "n: (BigInteger)".$modulus."\n";
echo "e: (BigInteger)".$exponent."\n";
$rsa->loadKey(array('n' => $modulus, 'e' => $exponent));
$rsa->setPublicKey();
$pubKey = $rsa->getPublicKey();
echo "Public Key from phpseclib\n".$pubKey."\n";
echo "--First openSSL error check--\n";
while ($msg = openssl_error_string())
echo $msg . "<br />\n";
echo "--After First Error Check, before Verify--\n";
$res = $rsa->verify($pieces[0].".".$pieces[1], $signature);
while ($msg = openssl_error_string())
echo $msg . "<br />\n";
echo "--Verify result: ".var_export($res, true)."--\n";
}
输出
Found in list: kid=6c781942d849ba2ecda8cedb72d34357fc95b327 n: (base64URL)s1dt5wFFaYl-Bt7Yb7QgWEatLJfxwWDhbd5yvm2Z4d1PRgNVQa9kwOArQNoOJ-b-oZnXLVFsVASUXEAumGf1ip5TVCQmMBKqlchSDNuoZfoWdpCCX7jx4gNuS43pS6VqV3QDjWnoXRTHaUi5pZEbpAmWpOeG_CfmewNVwBXPFx8-mtvEdtxIrspX4ayXTViR4vHc7MhQhUxllFbocxMjJysDQuZV9wN3MI0lVtQdf52SKJwF3lhvWA9-WAEZ1q8wq-I93Sfte95RaFjDqCH--Sh-8DjhK4OvgItcEGd5QRHjdLvrayPwaDQbpMRN2n3BkVWIxKJubtRiSeWbawCklQ e: (base64URL)AQAB n: (base64)s1dt5wFFaYl+Bt7Yb7QgWEatLJfxwWDhbd5yvm2Z4d1PRgNVQa9kwOArQNoOJ+b+oZnXLVFsVASUXEAumGf1ip5TVCQmMBKqlchSDNuoZfoWdpCCX7jx4gNuS43pS6VqV3QDjWnoXRTHaUi5pZEbpAmWpOeG/CfmewNVwBXPFx8+mtvEdtxIrspX4ayXTViR4vHc7MhQhUxllFbocxMjJysDQuZV9wN3MI0lVtQdf52SKJwF3lhvWA9+WAEZ1q8wq+I93Sfte95RaFjDqCH++Sh+8DjhK4OvgItcEGd5QRHjdLvrayPwaDQbpMRN2n3BkVWIxKJubtRiSeWbawCklQ e: (base64)AQAB n: (BigInteger)18674717054764783973087488855176842456138281065703345249166514684640666364313492818979675328236363014396820758462507776710767978395332237045824933690552916871072924852353561300648679961653291310130667565640227949181785672954620248276915721938277908962537175894062430220752771265500386404609948390377043762106166027544443459977210114747088393335234720657330424186435226141073425445733987857419933850994487913462193466159335385639996611717486282518255208499657362420183528330692236194252505592468150318350852955051377118157817611947817677975817359347998935961426571802421142861030565807099600656362069178972477827638867161671399657071319083914500667014214521757304661303525496653078786180348831678824969667950119891369610525474165187687495455755684504105433077872587114630537058768184460798470456362909589578101896361255070801 e: (BigInteger)1095844162 Public Key from phpseclib -----BEGIN PUBLIC KEY----- MIIBeDANBgkqhkiG9w0BAQEFAAOCAWUAMIIBYAKCAVZzMWR0NXdGRmFZbCtCdDdZ YjdRZ1dFYXRMSmZ4d1dEaGJkNXl2bTJaNGQxUFJnTlZRYTlrd09BclFOb09KK2Ir b1puWExWRnNWQVNVWEVBdW1HZjFpcDVUVkNRbU1CS3FsY2hTRE51b1pmb1dkcEND WDdqeDRnTnVTNDNwUzZWcVYzUURqV25vWFJUSGFVaTVwWkVicEFtV3BPZUcvQ2Zt ZXdOVndCWFBGeDgrbXR2RWR0eElyc3BYNGF5WFRWaVI0dkhjN01oUWhVeGxsRmJv Y3hNakp5c0RRdVpWOXdOM01JMGxWdFFkZjUyU0tKd0YzbGh2V0E5K1dBRVoxcTh3 cStJOTNTZnRlOTVSYUZqRHFDSCsrU2grOERqaEs0T3ZnSXRjRUdkNVFSSGpkTHZy YXlQd2FEUWJwTVJOMm4zQmtWV0l4S0p1YnRSaVNlV2Jhd0NrbFECBEFRQUI= -----END PUBLIC KEY----- --First openSSL error check-- --After First Error Check, before Verify-- error:0906D06C:PEM routines:PEM_read_bio:no start line
--Verify result: false--
答案 0 :(得分:2)
所以对于从搜索引擎来这里的人来说:
我尝试使用Google ID令牌验证我的登录凭据是否为:
准确
不是欺骗的
能够由后端服务器检查
使用数学计算,所以我不必每次都查询谷歌(增加延迟和if-anything-can-go-wrong-it-will效果)
我意识到大多数人肯定能够阅读这段代码,但我想打字来解释下一个被激怒的灵魂正在发生的事情。
你的第一部分可能会有所不同,因为我来自Android,并且从那里开始相当直接。
我的流程是在Android中请求令牌。 (仅显示与示例和相关部分的差异)
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) .requestIdToken(getString(R.string.client_id)) .requestEmail() .build();
从活动结果(onActivityResult)获取令牌
GoogleSignInAccount acct = result.getSignInAccount(); String idToken = acct.getIdToken();
令牌由3个部分组成,以句点分隔,格式为“$ header。$ info。$ signature”。我们将使用“$ signature”验证“$ header。$ info”。
$ header包含有关加密的信息,例如(解码后):
{"alg":"RS256","kid":"6c781942d849ba2ecda8cedb72d34357fc95b327"}
所以使用的算法是“SHA-256,带有RSA加密”,密钥库中的密钥ID是6c781942d849ba2ecda8cedb72d34357fc95b327。我们稍后会用到它。
通过HTTP
将整个令牌传递给我的后端服务器然后使用以下代码解码令牌,直接取自接受的答案
include('Crypt/RSA.php'); //path to phpseclib
$modulus = "";
$exponent = "";
$token = $_POST['token'];
$pieces = explode(".", $token);
$data = $pieces[0].".".$pieces[1];
$signature = base64_decode(str_replace(['-','_'], ['+','/'], $pieces[2]));
$header = json_decode(base64_decode(str_replace(['-','_'], ['+','/'], $pieces[0])), true);
$alg = $header['alg'];
$kid = $header['kid'];
if (testGoogleList($alg, $kid, $modulus, $exponent))
{
$modulus = base64_decode(str_replace(['-','_'], ['+','/'], $modulus));
$exponent = base64_decode(str_replace(['-','_'], ['+','/'], $exponent));
$rsa = new Crypt_RSA();
$rsa->loadKey([
'n' => new Math_BigInteger($modulus, 256),
'e' => new Math_BigInteger($exponent, 256)
]);
$rsa->setHash('sha256');
$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
if ($rsa->verify($data, $signature))
{
echo "VALID!!!!";
} else {
echo "NOT VALID :'(";
}
}
我们base64_decode(str_replace(['-','_'], ['+','/'], $VARIABLE))
的原因是因为它们以base64URL
形式呈现,其中'+'更改为' - ','/'更改为'_'。所以我们从base64URL&gt;更改它base64&gt;未编码的(普通)文本。
这是做什么的?
我把它包装在一个函数中,但我的函数testGoogleList
基本上是这样的:
如果没有,我们会继续,否则请跳到第4步。
如果我们在缓存中找到密钥,我们从中提取“n”(我们将其称为“模数”)和“e”(“指数”)部分并将其传回。< / p>
然后我们从base64URL&gt;解码模数和指数片段。 base64&gt;未加密的(普通)文本。
在此之后,由你自己做的事情取决于你。
再次感谢neubert的帮助!
答案 1 :(得分:0)
问题在于你不能解码任何相关的东西。
这对我有用(告诉我签名是有效的):
<?php
include('Crypt/RSA.php');
$data = 'eyJhbGciOiJSUzI1NiIsImtpZCI6IjZjNzgxOTQyZDg0OWJhMmVjZGE4Y2VkYjcyZDM0MzU3ZmM5NWIzMjcifQ.eyJpc3MiOiJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20iLCJhdWQiOiIxMDQ5MTQ4MTU2NTQ2LTk2YjFxcTJsNTJtODVtODB0ZHVoZHVma2RwODRtN2tuLmFwcHMuZ29vZ2xldXNlcmNvbnRlbnQuY29tIiwic3ViIjoiMTEyNTk4NDgzNjQ2MjY1OTYxNTQwIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImF6cCI6IjEwNDkxNDgxNTY1NDYtdjJwZjRlbGhzOGNwcXBlcWZkMzU5am5nOWs5aW5kcTQuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJlbWFpbCI6InRlc3R1c2VydGh4QGdtYWlsLmNvbSIsImlhdCI6MTQ3NDc1NDMzMiwiZXhwIjoxNDc0NzU3OTMyLCJuYW1lIjoiVGVzdCBVc2VyIiwicGljdHVyZSI6Imh0dHBzOi8vbGg0Lmdvb2dsZXVzZXJjb250ZW50LmNvbS8tU0dldkZZRDlaWFEvQUFBQUFBQUFBQUkvQUFBQUFBQUFBQUEvQVBhWEhoUmtuX1hEaEhNLTEzeVMwTUtBcFNrZG1zVEdYdy9zOTYtYy9waG90by5qcGciLCJnaXZlbl9uYW1lIjoiVGVzdCIsImZhbWlseV9uYW1lIjoiVXNlciIsImxvY2FsZSI6ImVuIn0';
$signature = 'btukbBvhek6w14CrBVTGs8X9_IXIHZKpV1NzJ3OgbGUfmoRMirNGzZiFAgrR7COTeDJTamxRzojxxmXx6EEkQqNQcbyN8dO0PTuNt9pujQjLbFw_HBhIFJQaJSR3-tYPN-UtHGQ5JAAySsvCPapXbxyiKzTyvGYRSU65LmyNuiGxe6RQe1zHjq2ABJ4IPRqKPuFupnGRPWYyBSTPU7XQvtfhgyqA0BWZUfmCIFyDxQhvMaXNLTs01gnGVhcUDWZLi9vuUiKUlz3-aSSbwdfCMAljhBHnjpYO6341k5-qmgKkWawv8DX_nMEzntsCMCr664rP4wFEbsRB5ledM9Pc9Q';
$signature = str_replace(['-','_'], ['+','/'], $signature);
$signature = base64_decode($signature);
$n = 's1dt5wFFaYl-Bt7Yb7QgWEatLJfxwWDhbd5yvm2Z4d1PRgNVQa9kwOArQNoOJ-b-oZnXLVFsVASUXEAumGf1ip5TVCQmMBKqlchSDNuoZfoWdpCCX7jx4gNuS43pS6VqV3QDjWnoXRTHaUi5pZEbpAmWpOeG_CfmewNVwBXPFx8-mtvEdtxIrspX4ayXTViR4vHc7MhQhUxllFbocxMjJysDQuZV9wN3MI0lVtQdf52SKJwF3lhvWA9-WAEZ1q8wq-I93Sfte95RaFjDqCH--Sh-8DjhK4OvgItcEGd5QRHjdLvrayPwaDQbpMRN2n3BkVWIxKJubtRiSeWbawCklQ';
$n = str_replace(['-','_'], ['+','/'], $n);
$n = base64_decode($n);
$e = 'AQAB';
$e = base64_decode($e);
$rsa = new Crypt_RSA();
$rsa->loadKey([
'n' => new Math_BigInteger($n, 256),
'e' => new Math_BigInteger($e, 256)
]);
$rsa->setHash('sha256');
$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
echo $rsa->verify($data, $signature) ?
'valid' :
'invalid';