项目中需要接入苹果GameCenter。第三方服务器不能单纯依靠从GameCenter获取到PlayerID依靠从作为判断玩家的唯一标识,所以通常需要对玩家进行另外的验证。苹果官方给出了解答方案:https://developer.apple.com/library/mac/documentation/GameKit/Reference/GKLocalPlayer_Ref/index.html#//apple_ref/occ/instm/GKLocalPlayer/generateIdentityVerificationSignatureWithCompletionHandler
大致说下参考了网上一些资料后自己实践的过程:
首先是客户端调用[GKLocalPlayergenerateIdentityVerificationSignatureWithCompletionHandler],会获得四个返回值:publicKeyUrl,signature, salt, timestamp。这里解释下四个参数:
publicKeyUrl是一个公钥的下载地址,NSURL类型,可直接转成NSString类型,进而再转成string类型供PHP传参;
timestamp是一个uint64_t类型的时间戳,同样先转NSString再转string使用。
重点是signature和salt,他们是NSData类型,需要使用base64Encode将其转化为NSString:
NSString*string = [signature base64EncodedStringWithOptions:0]; salt同理。然后在转为String传给php做参数。(此处尤其注意编码格式)
好,基础数据已备齐,将其传给PHP端,按文档要求进行操作验证。参数例:
$request['publicKeyUrl']= 'https://static.gc.apple.com/public-key/gc-prod-2.cer';
$request['playerID']= 'G:1234567890';
$request['signature']= 'aqMcUTjC26YuCcHUuSLqCkOA2LhujkdinDCV/3BQyloEyg0NJkAVLn4fM+ScIMbS+JI3HDwyQhLT7tdwN2BtQTjSTvyV509fy7c+SLcWxVZzxt8YxN4VNJHEo3meG9bdQ9gozAUfnkBzMwke5hpCJJOhMYNmy/pB284CuuLvNi00GiAnx5Ij2ZfPi8QEg7NRTfyOGiHPfQ5Ahb1lf7G3VmOaXJ0PWq1UoHHRNShC1deaPWClyUuVyiI7c0OudIig7sibV8TNLXBKORXEExGgSswTYKDOjPQ/Wzk02ZckZtBebZgvYgomPR37odT+5F9NH0nx1oblmHiBaqwsedrftg==';
$request['timestamp']= 1463472175011;
$request['salt'] = 'ejNzcg==';
简单处理下参数,注意signature和salt需用base64_decode进行解码:
$playerID= $request['playerID'];
$bundleID= 'com.abcedf.wasd';
$signature= base64_decode($request['signature']);
$timestamp= $request['timestamp'];
$salt= base64_decode($request['salt']);
参照网上大神的操作,对timestamp进行处理:
//Timestamp is unsigned 64-bit integer big endian
$highMap = 0xffffffff00000000;
$lowMap = 0x00000000ffffffff;
$higher = ($timestamp & $highMap)>>32;
$lower = $timestamp & $lowMap;
$timestamp = pack('NN', $higher, $lower);
然后 $data = $playerID.$bundleID.$timestamp.$salt;
接下来下载并解析公钥:
$public_key_url= $request['publicKeyUrl'];
$ssl_certificate= file_get_contents($public_key_url);
$pem= chunk_split(base64_encode($ssl_certificate), 64, "\n");
$pem= "-----BEGIN CERTIFICATE-----\n" . $pem . "-----END CERTIFICATE-----\n";
$pubkeyid= openssl_pkey_get_public($pem);
最后按文档进行签名验证:
// 此处注意苹果的验证已由过去的OPENSSL_ALGO_SHA1变更为OPENSSL_ALGO_SHA256,而OPENSSL_ALGO_SHA256是PHP5.4.8以上才支持的算法。
$ok= openssl_verify($data, $signature, $pubkeyid, OPENSSL_ALGO_SHA256);
openssl_free_key($pubkeyid);
if($ok == 1) {
echo “Singnature is good.”;
}elseif ($ok == 0) {
echo “Singnature is bad.”;
}else {
echo “Singnature is error.”;
}
主要参考:
http://stackoverflow.com/questions/17408729/how-to-authenticate-the-gklocalplayer-on-my-third-party-server
http://stackoverflow.com/questions/24621839/how-to-authenticate-the-gklocalplayer-on-my-third-party-server-using-php
次要参考:
https://segmentfault.com/q/1010000002705803 (方法和回答都有待验证。)