华为SDK接入时各种签名烦不胜烦,官方文档没有详细的DEMO,和调试工具,调试起来很吃力。踩了很多的坑最终才校验通过。
1、校验登录签名
参数:
public function callGameLoginService(){
$apiParams['appId'] = $this->appId;
$apiParams['cpId'] = $this->cpId;
$apiParams['playerId'] = $this->playerId;
$apiParams['playerLevel'] = $this->playerLevel;
$apiParams['playerSSign'] = $this->playerSSign;
$apiParams['private_key'] = $this->private_key;
$apiParams['public_key'] = $this->public_key;
$apiParams['ts'] = $this->ts;
$apiParams['method'] = 'external.hms.gs.checkPlayerSign';
$url = 'https://gss-cn.game.hicloud.com/gameservice/api/gbClientApi';
//构造源串
$key_string = $this->getSignContent($apiParams);
//获取签名
$apiParams['cpSign'] = $this->rsasign($key_string,$apiParams['private_key']);
Yii::error('tstststststststs+++++++++::'.$apiParams['playerSSign']);
$resp = json_decode($this->curl($url, $apiParams),true);
if($resp['rtnCode'] == 0){
//验证签名成功,保存更新用户信息
}else {
return json_encode(['code'=>1,'msg'=>'验证签名失败!']);
}
}
a、构造源串
protected function getSignContent($params) {
ksort($params);//先排序
$stringToBeSigned = "";
$i = 0;
foreach ($params as $k => $v) {
if (false === $this->checkEmpty($v) && "@" != substr($v, 0, 1)) {
// 转换成目标字符集
$v = urlencode($this->characet($v, "UTF-8"));//最好转化一下编码,每个参数必须urlebcode
if ($i == 0) {
$stringToBeSigned .= "$k" . "=" . "$v";
} else {
$stringToBeSigned .= "&" . "$k" . "=" . "$v";
}
$i++;
}
}
生成的源串格式如:method=external.hms.gs.checkPlayerSign&appId=10000&cpId=1000&ts=1350539672156&playerId=100&playerLevel=10&playerSSign=VUOoWexHeQC98OFHyWapgKSACDwBgEHWb6IvPutKO0Z/wSVU3SDoK7/vnaLsYte6cYJu/RVWxoGh8lJfHuMoMucKutoNEXnAnPgTG5cfXf79DCtTnhMJ3lHBjaYFD03RWb2XBRKlnF7m455DeU2bvPZOsi7BhTDNPD0bTxY7PWlASLCSX7C7WqHN4/AWxDiU+ki2pPBstuSDecoUQQATBU35bQE2V7DtOsoGAhseuKXZe7yExMqszyZHLKaaqsbqq1rCua6FvJtwlwO82eY7N5kyW29r3MQ/uW1XGh4aPDods9UfD90BSLoPPmLjV9tREX/HFIdxkZ3FVWbkcWR4YQ==
b、构造签名
protected function sign($data, $cpAuthKey) {
$res = "-----BEGIN RSA PRIVATE KEY-----\n" .
wordwrap($cpAuthKey, 64, "\n", true) .
"\n-----END RSA PRIVATE KEY-----";
openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256);
$sign = base64_encode($sign);
return $sign;
}
需要注意的是参与签名的私钥如果是写在配置中则不能换行,必须是完整的一行,否则会报错,如果是引入文件则不需要。
二、构造支付pay接口的sign
需要用到的参数:
$apiParams = array(
'productName' => $prod->product_name,
'productDesc' => $prod->product_desc,
'merchantId' => $config['merchantId'],
'applicationID' => $config['appId'],
'amount' => sprintf('%.2f',$prod->price),
'requestId' => $model->orderid,
'country' => $config['country'],
'currency' => $config['currency'],
'sdkChannel' => $config['sdkChannel'],
'urlver' => '2',
'url' => $config['url']
);
这些参数的参数值必须和客户端的完全一致。
a、构造源串,这里构造源串和登录时有些不同。
protected function getSignContent($params) {
ksort($params);//排序
$stringToBeSigned = "";
$i = 0;
foreach ($params as $k => $v) {
if (false === $this->checkEmpty($v) && "@" != substr($v, 0, 1)) {
// 转换成目标字符集
//$v = urlencode($this->characet($v, "UTF-8")); 不需要urlencode
if ($i == 0) {
$stringToBeSigned .= "$k" . "=" . "$v";
} else {
$stringToBeSigned .= "&" . "$k" . "=" . "$v";
}
$i++;
}
}
b、签名
protected function sign($data, $cpAuthKey) {
$res = "-----BEGIN RSA PRIVATE KEY-----\n" .
wordwrap($cpAuthKey, 64, "\n", true) .
"\n-----END RSA PRIVATE KEY-----";
openssl_sign($data, $sign, $res, OPENSSL_ALGO_SHA256);
$sign = base64_encode($sign);
return $sign;
}
签名方法没什么大的区别,需要注意的是这里的私钥是支付私钥