我正在尝试使用此library将Apple登录到Android应用中。文档中描述了主要流程:该库在Android端返回授权代码。此授权码必须发送到我的后端,然后,我的后端又将其发送到Apple服务器,以便取回访问令牌。
如here和here所述,为了获取访问令牌,我们需要向Apple API发送参数列表,授权代码和签名的JWT。特别是,JWT需要使用ES256算法使用.p8私钥进行签名,该私钥必须从Apple开发人员门户生成和下载。 Apple doc
这是我的PHP脚本:
<?php
$authorization_code = $_POST('auth_code');
$privateKey = <<<EOD
-----BEGIN PRIVATE KEY-----
my_private_key_downloaded_from_apple_developer_portal (.p8 format)
-----END PRIVATE KEY-----
EOD;
$kid = 'key_id_of_the_private_key'; //Generated in Apple developer Portal
$iss = 'team_id_of_my_developer_profile';
$client_id = 'identifier_setted_in_developer_portal'; //Generated in Apple developer Portal
$signed_jwt = $this->generateJWT($kid,$iss,$client_id,$privateKey);
$data = [
'client_id' => $client_id,'client_secret' => $signed_jwt,'code' => $authorization_code,'grant_type' => 'authorization_code'
];
$ch = curl_init();
curl_setopt($ch,CURLOPT_URL,'https://appleid.apple.com/auth/token');
curl_setopt($ch,CURLOPT_POST,1);
curl_setopt($ch,CURLOPT_POSTFIELDS,$data);
curl_setopt($ch,CURLOPT_RETURNTRANSFER,true);
$serverOutput = curl_exec($ch);
curl_close ($ch);
var_dump($serverOutput);
function generateJWT($kid,$sub,$key) {
$header = [
'alg' => 'ES256','kid' => $kid
];
$body = [
'iss' => $iss,'iat' => time(),'exp' => time() + 3600,'aud' => 'https://appleid.apple.com','sub' => $sub
];
$privKey = openssl_pkey_get_private($key);
if (!$privKey) return false;
$payload = $this->encode(json_encode($header)).'.'.$this->encode(json_encode($body));
$signature = '';
$success = openssl_sign($payload,$signature,$privKey,OPENSSL_ALGO_SHA256);
if (!$success) return false;
return $payload.'.'.$this->encode($signature);
}
function encode($data) {
$encoded = strtr(base64_encode($data),'+/','-_');
return rtrim($encoded,'=');
}
?>
问题在于Apple的回应总是:
{"error":"invalid_client"}
阅读here似乎问题可能与openSSL有关,后者生成的签名对Apple不正确(“ OpenSSL的ES256签名结果是DER编码的Asn.1结构(其大小超过64)。(不是原始R || S值)“)。
是否可以使用openSSL获得正确的签名?
p8格式是openssl_sign和openssl_pkey_get_private函数的正确输入吗? (我注意到提供的.p8密钥如果在jwt.io中用于计算签名的jwt,则无法使用。)
在openSSL文档中,我读到应该提供一个pem密钥,如何在.pem密钥中转换.p8?
我还尝试了一些PHP库,它们基本上使用了与上述相同的步骤,例如firebase/php-jwt和lcobucci/jwt,但是Apple的响应仍然是“无效的客户端”。
预先感谢您的帮助,
编辑
我试图从等式中完全删除openSSL。使用从.p8生成的.pem密钥,我用jwt.io生成了一个签名的JWT。使用此签名的JWT,Apple API可以正确答复。至此,我几乎可以确定这是一个openSSL签名问题。关键问题是如何使用PHP和openSSL获得正确的ES256签名。