第三方服务器用PHP验证GameCenter GKLocalPlayer返回的签名

       项目中需要接入苹果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  (方法和回答都有待验证。)




猜你喜欢

转载自blog.csdn.net/Gao_sun/article/details/51694781