李帅

1.打印苹果日志

......@@ -13,16 +13,19 @@ use App\Models\Order;
use App\Models\User;
use App\Models\UserProfile;
use Carbon\Carbon;
use Firebase\JWT\SignatureInvalidException;
use GuzzleHttp\Client;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Redis;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Illuminate\Support\Facades\File;
class ApplePayment implements PaymentInterface
{
const IS_SANDBOX = true;
const CA_PATH = "/AppleRootCA-G3.pem";
public function __construct()
{
......@@ -48,7 +51,6 @@ class ApplePayment implements PaymentInterface
public function notifySandbox($string)
{
Log::debug('sandbox返回的数据:====================');
Log::debug($string);
$components = explode('.',$string);
if (count($components) < 3){
......@@ -58,6 +60,105 @@ class ApplePayment implements PaymentInterface
$header = json_decode(base64_decode($components[0]),true);
Log::debug(print_r($header,true));
// 这一步可以省略,不需要验证根证书
$this->validateAppleRootCa($header);
$responseBodyPayload = $this->decodeCertificate($string, $header['x5c'][0]);
Log::debug(print_r($responseBodyPayload,true));
/**{
"notificationType": "SUBSCRIBED"
"subtype": "RESUBSCRIBE"
"notificationUUID": "99e65e59-c178-4f49-8b83-ea7d916cb568"
"data": {
"bundleId": "ink.parlando.parlando"
"bundleVersion": "13"
"environment": "Sandbox"
"signedTransactionInfo": "xxx"
"signedRenewalInfo": "xxx"
}
"version": "2.0"
"signedDate": 1671451705697
}
*/
$signedTransactionInfoString = $responseBodyPayload['data']['signedTransactionInfo'];
$components = explode('.',$signedTransactionInfoString);
$header = json_decode(base64_decode($components[0]),true);
if (count($components) < 3){
Log::error("jwt错误");
return false;
}
$signedTransactionInfo = $this->decodeCertificate($string, $header['x5c'][0]);
Log::debug(print_r($signedTransactionInfo,true));
/**{
"transactionId": "2000000231419425"
"originalTransactionId": "2000000229164150"
"webOrderLineItemId": "2000000017115109"
"bundleId": "ink.parlando.parlando"
"productId": "monthly_yiyan_vip"
"subscriptionGroupIdentifier": "21080623"
"purchaseDate": 1671451694000
"originalPurchaseDate": 1671123372000
"expiresDate": 1671451994000
"quantity": 1
"type": "Auto-Renewable Subscription"
"inAppOwnershipType": "PURCHASED"
"signedDate": 1671451705700
"environment": "Sandbox"
}*/
$signedRenewalInfoString = $responseBodyPayload['data']['signedRenewalInfo'];
$components = explode('.',$signedRenewalInfoString);
$header = json_decode(base64_decode($components[0]),true);
if (count($components) < 3){
Log::error("jwt错误");
return false;
}
$signedRenewalInfo = $this->decodeCertificate($string, $header['x5c'][0]);
Log::debug(print_r($signedRenewalInfo,true));
/**{
"originalTransactionId": "2000000229164150"
"autoRenewProductId": "monthly_yiyan_vip"
"productId": "monthly_yiyan_vip"
"autoRenewStatus": 1
"signedDate": 1671451705673
"environment": "Sandbox"
"recentSubscriptionStartDate": 1671451694000
}*/
}
private function validateAppleRootCa($header)
{
$lastIndex = count($header['x5c']) - 1;
$certificate = $this->getCertificate($header['x5c'][$lastIndex]);
if ($certificate != File::get(public_path(self::CA_PATH))) return false;
return true;
}
private function getCertificate($string)
{
$certificate = "-----BEGIN CERTIFICATE-----" . PHP_EOL;
$certificate .= chunk_split($string, 64, PHP_EOL);
$certificate .= "-----END CERTIFICATE-----" . PHP_EOL;
return $certificate;
}
private function decodeCertificate($string, $appleCertificate)
{
$certificate = $this->getCertificate($appleCertificate);
$cert_object = openssl_x509_read($certificate);
$pkey_object = openssl_pkey_get_public($cert_object);
$pkey_array = openssl_pkey_get_details($pkey_object);
$public_key = $pkey_array["key"];
try{
$decode = JWT::decode($string, new Key($public_key, "ES256"));
return (array)$decode;
}catch (SignatureInvalidException $exception){
Log::error("Signature Invalid!");
return false;
}
}
}
\ No newline at end of file
......
-----BEGIN CERTIFICATE-----
MIICQzCCAcmgAwIBAgIILcX8iNLFS5UwCgYIKoZIzj0EAwMwZzEbMBkGA1UEAwwS
QXBwbGUgUm9vdCBDQSAtIEczMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0aW9u
IEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UEBhMCVVMwHhcN
MTQwNDMwMTgxOTA2WhcNMzkwNDMwMTgxOTA2WjBnMRswGQYDVQQDDBJBcHBsZSBS
b290IENBIC0gRzMxJjAkBgNVBAsMHUFwcGxlIENlcnRpZmljYXRpb24gQXV0aG9y
aXR5MRMwEQYDVQQKDApBcHBsZSBJbmMuMQswCQYDVQQGEwJVUzB2MBAGByqGSM49
AgEGBSuBBAAiA2IABJjpLz1AcqTtkyJygRMc3RCV8cWjTnHcFBbZDuWmBSp3ZHtf
TjjTuxxEtX/1H7YyYl3J6YRbTzBPEVoA/VhYDKX1DyxNB0cTddqXl5dvMVztK517
IDvYuVTZXpmkOlEKMaNCMEAwHQYDVR0OBBYEFLuw3qFYM4iapIqZ3r6966/ayySr
MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2gA
MGUCMQCD6cHEFl4aXTQY2e3v9GwOAEZLuN+yRhHFD/3meoyhpmvOwgPUnPWTxnS4
at+qIxUCMG1mihDK1A3UT82NQz60imOlM27jbdoXt2QfyFMm+YhidDkLF1vLUagM
6BgD56KyKA==
-----END CERTIFICATE-----