如何在服务端(PHP)生成并加密JSON Web Token (JWT)+向APNs发送远程推送请求

2,349 阅读1分钟

在拿到App发送过来的deviceToken和产品经理的推送payload之后,作为服务端程序员的我们,还需要做一个操作,那就是生成并加密JSON Web Token (JWT),然后才能把这三个一起发送给APNs。

关于JWT身份验证令牌的概念以及如何在苹果开发者网站获取签名密钥(Key)在我的教程中都有讲解,不熟悉的同学可以再去看一下。

这里主要说一下如何在服务端用PHP语言

1.生成并加密JWT

2.向APNs发送推送请求

使用框架:jwt-framework

1.生成并加密JWT

用composer安装这个框架包:

composer require web-token/jwt-framework

在文件中引入:

<?php
require_once 'vendor/autoload.php';
use Jose\Component\Core\AlgorithmManager;
use Jose\Component\Core\Converter\StandardConverter;
use Jose\Component\KeyManagement\JWKFactory;
use Jose\Component\Signature\JWSBuilder;
use Jose\Component\Signature\Algorithm\ES256;
use Jose\Component\Signature\Serializer\CompactSerializer;

创建JWT:

<?php
function getToken($cerPath, $keyID, $teamId) {
	// 1.创建ES256算法
	$algorithmManager = AlgorithmManager::create([ 
		new ES256() 
	]);
	
	// 2.用苹果开发者网站创建的p8文件(签名密钥)创建JSON web key($cerPath为p8文件的路径)
	$jwk = JWKFactory::createFromKeyFile($cerPath);
	
	// JSON转化器
	$jsonConverter = new StandardConverter();
	// 实例化JWSBuilder
	$jwsBuilder = new JWSBuilder(
	    $jsonConverter,
	    $algorithmManager
	);
	
	// 3.创建JWT的payload部分(iat为当前时间戳,iss为开发者账号TeamID)
	$payload = $jsonConverter->encode([
	    'iat' => time(),
	    'iss' => $teamId,
	]);
	
	// 4.生成并加密JWT
	$jws = $jwsBuilder
	    ->create()                                                  // 创建
	    ->withPayload($payload)                                     // 设定JWT的payload
	    ->addSignature($jwk, ['alg' => 'ES256', 'kid' => $keyID])  // 用JSON web key和苹果规定的JWTheader签名加密
	    ->build();                                                  // 生成
	$serializer = new CompactSerializer($jsonConverter); // 序列化工具
	
	// 5.序列化JWT
	$token = $serializer->serialize($jws); // 序列化上面的jws,只有一个签名,故index为0的即可
	
	return $token;
}

2.向APNs发送推送请求

<?php
function sendPush($deviceToken, $authToken, $payload) {
	// 1.创建一个带有deviceToken的path(其实就是字串)-苹果规定必须这么写
	$path = '/3/device/'.$deviceToken;
	
	$curl = curl_init();
	
	curl_setopt_array($curl, array(
	  // 2.带上deviceToken向APNs服务器请求
	  CURLOPT_URL => "https://api.development.push.apple.com:443".$path,
	  CURLOPT_RETURNTRANSFER => true,
	  CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_2_0,
	  CURLOPT_TIMEOUT => 30,
	  CURLOPT_CUSTOMREQUEST => "POST",
	  // 3.把推送的payload放入请求体+设置请求头
	  CURLOPT_POSTFIELDS => $payload,
	  CURLOPT_HTTPHEADER => array(
	    "Content-Type: application/json",
	    "apns-expiration: 0",
	    "apns-push-type: alert",
	    "apns-topic: com.example.app", // 4.我们App的bundleID
	    "authorization: bearer ".$authToken // 5.上面生成并加密的JWT
	  ),
	));
	
	//发送请求
	$response = curl_exec($curl);
	
	$err = curl_error($curl);
	curl_close($curl);
	
	if ($err) {
	  echo "cURL Error #:" . $err;
	} else {
	  echo $response;
	}
}

调用上述两个函数并传参:

<?php
$token = getToken('key/path/mykey.p8', 'Key ID', 'Team ID');
$payload = json_encode(['aps' => ['alert' => 'Hi there!']]);
sendPush('9fbb61136e03c.................', $token, $payload);