问题
Apple recently added a new authentication method to APNS ( Apple Push Notification Authentication Key (Sandbox & Production)).
The downloaded key is a .p8
file with a private key:
$ cat APNSAuthKey_3HHEB343FX.p8
-----BEGIN PRIVATE KEY-----
MIGTAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBH...Already.Revoked...lHEjCX1v51W
-----END PRIVATE KEY-----
I am using APNs messages using the old method - adding them to keychain, asking for a certificate and using OpenSSL to send messages to gateway.production.push.apple.com:2195
.
How do I send push notifications using standard CLI Linux tools (OpenSSL, Python etc.) using the new format?
回答1:
If you have curl with HTTP/2 support and openssl with ECDSA support installed on your machine, you can use the following script to test push notifications using an APNs Auth Key:
#!/bin/bash
deviceToken=b27371497b85611baf9052b4ccfb9641ab7fea1d01c91732149c99cc3ed9342f
authKey="./APNSAuthKey_ABC1234DEF.p8"
authKeyId=ABC1234DEF
teamId=TEAM123456
bundleId=com.example.myapp
endpoint=https://api.development.push.apple.com
read -r -d '' payload <<-'EOF'
{
"aps": {
"badge": 2,
"category": "mycategory",
"alert": {
"title": "my title",
"subtitle": "my subtitle",
"body": "my body text message"
}
},
"custom": {
"mykey": "myvalue"
}
}
EOF
# --------------------------------------------------------------------------
base64() {
openssl base64 -e -A | tr -- '+/' '-_' | tr -d =
}
sign() {
printf "$1" | openssl dgst -binary -sha256 -sign "$authKey" | base64
}
time=$(date +%s)
header=$(printf '{ "alg": "ES256", "kid": "%s" }' "$authKeyId" | base64)
claims=$(printf '{ "iss": "%s", "iat": %d }' "$teamId" "$time" | base64)
jwt="$header.$claims.$(sign $header.$claims)"
curl --verbose \
--header "content-type: application/json" \
--header "authorization: bearer $jwt" \
--header "apns-topic: $bundleId" \
--data "$payload" \
$endpoint/3/device/$deviceToken
NOTE: I use a slight variation of this script for testing on macOS with homebrew versions of curl and openssl: http://thrysoee.dk/apns/
回答2:
You can send push notification by NODE JS using Apple Push Notification Authentication Key (Sandbox & Production). There is a tutorial provided by Elad Nava in this link
This tutorial has all steps of creating the Apple Push Notification Authentication Key and setting up a local server to run Node JS code for sending push notification. You can run the code in your local machine and test the push notification.
Hope this will help.
回答3:
Voilà in PHP what it looks like with curl and HTTP/2. This script return the 200 ok status code along with the generated token id.
// THE FINAL SCRIPT WITHOUT DEPENDENCIES!!! ...except curl with http2
$device_token = "a0abd886etc...";
//echo $key;
$kid = "YOURKEYID";
$teamId = "YOURTEAMID";
$app_bundle_id = "your.app.bundle";
$base_url = "https://api.development.push.apple.com";
$header = ["alg" => "ES256", "kid" => $kid];
$header = base64_encode(json_encode($header));
$claim = ["iss" => $teamId, "iat" => time()];
$claim = base64_encode(json_encode($claim));
$token = $header.".".$claim;
// key in same folder as the script
$filename = "KeyFromApple.p8";
$pkey = openssl_pkey_get_private("file://{$filename}");
$signature;
openssl_sign($token, $signature, $pkey, 'sha256');
$sign = base64_encode($signature);
$jws = $token.".".$sign;
$message = '{"aps":{"alert":"You are welcome.","sound":"default"}}';
function sendHTTP2Push($curl, $base_url, $app_bundle_id, $message, $device_token, $jws) {
$url = "{$base_url}/3/device/{$device_token}";
// headers
$headers = array(
"apns-topic: {$app_bundle_id}",
'Authorization: bearer ' . $jws
);
// other curl options
curl_setopt_array($curl, array(
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0,
CURLOPT_URL => $url,
CURLOPT_PORT => 443,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_POST => TRUE,
CURLOPT_POSTFIELDS => $message,
CURLOPT_RETURNTRANSFER => TRUE,
CURLOPT_TIMEOUT => 30,
CURLOPT_SSL_VERIFYPEER => FALSE,
CURLOPT_HEADER => 1
));
// go...
$result = curl_exec($curl);
if ($result === FALSE) {
throw new Exception("Curl failed: " . curl_error($curl));
}
print_r($result."\n");
// get response
$status = curl_getinfo($curl);
return $status;
}
// open connection
$curl = curl_init();
sendHTTP2Push($curl, $base_url, $app_bundle_id, $message, $device_token, $jws);
回答4:
The answer provided by Nicolas Manzini, while helpful, did not fully work for me. I also wanted to use command line curl. In particular, reading in the .p8 file was causing some problems. A modified version:
<?php
$teamid = 'YOURTEAMID';
$keyid = 'A464FN6T93'; // in the name of the file downloaded from Apple Certs
// since it is a universal key, I wanted this in a location accessible to several accounts
$keyFile = '/path/to/file/AuthKey_A464FN6T93.p8';
$privateKey = openssl_pkey_get_private('file://' . $keyFile);
if (! $privateKey) {
die('could not find: ' . $keyFile);
}
$header = ['alg' => 'ES256', 'kid' => $keyid];
$header = base64_encode(json_encode($header));
$claim = ['iss' => $teamid, 'iat' => time()];
$claim = base64_encode(json_encode($claim));
$tok = $header . '.' . $claim;
// pass in empty $signature, 2nd line below fills it
$signature = '';
$result = openssl_sign($tok, $signature, $privateKey, OPENSSL_ALGO_SHA256); // 'sha256'
if (! $result) {
die('unable to create signature');
}
$sign = base64_encode($signature);
openssl_free_key($privateKey);
$jwt = $tok . '.' . $sign;
foreach($tokens as $token) {
$cmd = '\
/usr/local/bin/curl -v \
-d \'{"aps":{"alert":{"title":"Notification Title","body":"You are being notified!"},"sound":"default"}}\' \
-H "apns-topic: com.app.bundle.id" \
-H "authorization: bearer ' . $jwt . '" \
-H "content-type:application/json" \
--http2 \
https://api.push.apple.com/3/device/' . $token . ' 2>&1'; // ending w/ 2>&1, sends output to $output
exec($cmd, $output, $return);
if ($return != 0) {
// be notified of error
}
else {
foreach($output as $line) {
if (strpos($line, 'apns-id')) {
$apns = $line;
}
}
}
}
?>
来源:https://stackoverflow.com/questions/39943701/how-to-send-apns-push-messages-using-apns-auth-key-and-standard-cli-tools