1. 首先阅读官网文档 https://developer.apple.com/documentation/signinwithapplerestapi
重点讲解苹果授权登陆 后端PHP如何验证
1. identityToken 的验证:
客户端会向后端 传递 userId identityToken email 等参数
后端必须要验证 identityToken 的有效性,合法性;关于为什么要验证 可以阅读官方文档:
identityToken 是 JWT算法格式
使用到的Apple公钥接口:GET https://appleid.apple.com/auth/keys
返回如下:
{
"keys": [
{
"kty": "RSA",
"kid": "AIDOPK1",
"use": "sig",
"alg": "RS256",
"n": "lxrwmuYSAsTfn-lUu4goZSXBD9ackM9OJuwUVQHmbZo6GW4Fu_auUdN5zI7Y1dEDfgt7m7QXWbHuMD01HLnD4eRtY-RNwCWdjNfEaY_esUPY3OVMrNDI15Ns13xspWS3q-13kdGv9jHI28P87RvMpjz_JCpQ5IM44oSyRnYtVJO-320SB8E2Bw92pmrenbp67KRUzTEVfGU4-obP5RZ09OxvCr1io4KJvEOjDJuuoClF66AT72WymtoMdwzUmhINjR0XSqK6H0MdWsjw7ysyd_JhmqX5CAaT9Pgi0J8lU_pcl215oANqjy7Ob-VMhug9eGyxAWVfu_1u6QJKePlE-w",
"e": "AQAB"
}
]
}
kid,为密钥id标识,签名算法采用的是RS256(RSA 256 + SHA 256),kty常量标识使用RSA签名算法,其公钥参数为n和e
需要使用n和e 生产公钥方法如下:
/**
*
* Create a public key represented in PEM format from RSA modulus and exponent information
*
* @param string $n the RSA modulus encoded in Base64
* @param string $e the RSA exponent encoded in Base64
* @return string the RSA public key represented in PEM format
*/
private static function createPemFromModulusAndExponent($n, $e)
{
$modulus = JWT::urlsafeB64Decode($n);
$publicExponent = JWT::urlsafeB64Decode($e);
$components = array(
'modulus' => pack('Ca*a*', 2, self::encodeLength(strlen($modulus)), $modulus),
'publicExponent' => pack('Ca*a*', 2, self::encodeLength(strlen($publicExponent)), $publicExponent)
);
$RSAPublicKey = pack(
'Ca*a*a*',
48,
self::encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
$components['modulus'],
$components['publicExponent']
);
// sequence(oid(1.2.840.113549.1.1.1), null)) = rsaEncryption.
$rsaOID = pack('H*', '300d06092a864886f70d0101010500'); // hex version of MA0GCSqGSIb3DQEBAQUA
$RSAPublicKey = chr(0) . $RSAPublicKey;
$RSAPublicKey = chr(3) . self::encodeLength(strlen($RSAPublicKey)) . $RSAPublicKey;
$RSAPublicKey = pack(
'Ca*a*',
48,
self::encodeLength(strlen($rsaOID . $RSAPublicKey)),
$rsaOID . $RSAPublicKey
);
$RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
chunk_split(base64_encode($RSAPublicKey), 64) .
'-----END PUBLIC KEY-----';
return $RSAPublicKey;
}
--------------------------------------------------------------
$pem = self::createPemFromModulusAndExponent($source['n'], $source['e']);
$pKey = openssl_pkey_get_public($pem);
$publicKeyDetails = openssl_pkey_get_details($pKey);
return [
'publicKey' => $publicKeyDetails['key'],
'alg' => $parsedKeyData['alg']
];
得到 $publicKeyDetails['key'] 这个公钥后 就可以使用它来 验证 identityToken的签名的合法性了:
$publicKey = $publicKeyData['publicKey'];
$alg = $publicKeyData['alg'];
$payload = JWT::decode($identityToken, $publicKey, [$alg]);
verify("$headb64.$bodyb64", $sig, $key, $header->alg)
-------------------------------------------------------
//verify中核心方法:
$success = openssl_verify($msg, $signature, $key, $algorithm);
identityToken:
'eyJraWQiOiJBSURPUEsxIiwiYWxnIjoiUlMyNTYifQ.eyJpc3MiOiJodHRwczovL2FwcGxlaWQuYXBwbGUuY29tIiwiYXVkIjoiY29tLkxCTS5Wb2NhbE1hdGUiLCJleHAiOjE1NzIzMjA5MDUsImlhdCI6MTU3MjMyMDMwNSwic3ViIjoiMDAxMzA5LjI4Zjk0NGZkYjlhYjQ4YzliMGUyNTZlMDA5ZTZiOGIwLjA3MjIiLCJjX2hhc2giOiJTSUhWWE1QTjFibEJiN0RSZ2hYWjl3IiwiZW1haWwiOiJncWFjaWJ4eWh1QHByaXZhdGVyZWxheS5hcHBsZWlkLmNvbSIsImVtYWlsX3ZlcmlmaWVkIjoidHJ1ZSIsImlzX3ByaXZhdGVfZW1haWwiOiJ0cnVlIiwiYXV0aF90aW1lIjoxNTcyMzIwMzA1fQ.RAXfYah9_owBatsmNTAMWD8eL1WXWO1quVetx1wMPqnZcr2DbrjHznL-g1LCxksIL0W3XuDMqxuU63ov_CXMVKFtHC86Bv6ab5p5CcIpIOGzRd5qnT7DrPDBV6JL822U09GubCbqZ22PD4m7wIRrggQ_V80GkHVH3M81TSJs6VAbTExjRg6RgFhofDWbMsT0h95b77jvTYbV1JzLRGgB1j6AE_CeMUKyGb3rSh0SGCkUX52IOJ2oCqQpB6dsZWS_90TJhCGyuHzfZHAhU7uRZoGvUVaIS212YhxqUvBozis3ZarEPYzGfCYlFMkLyduOvtPu_TEs_8hmljtNeFZZLw';
解析后如下:
HEADER:
{
"kid": "AIDOPK1",
"alg": "RS256"
}
PAYLOAD:
{
"iss": "https://appleid.apple.com",
"aud": "com.LBM.VocalMate",
"exp": 1572320905,
"iat": 1572320305,
"sub": "001309.28f944fdb9ab48c9b0e256e009e6b8b0.0722",
"c_hash": "SIHVXMPN1blBb7DRghXZ9w",
"email": "[email protected]",
"email_verified": "true",
"is_private_email": "true",
"auth_time": 1572320305
}
完整的验证identityToken的代码可参考:https://github.com/GriffinLedingham/php-apple-signin