现在对接游戏,无论是登录还是支付都是要去对接防沉迷实名认证接口,但前期的话你要登录网络游戏防沉迷实名认证系统进行接口测试,$appid ,$bizId,$key去接口测试页面找(正式上线在密钥管理),接下来跟大家说说调试步骤:
第一步:配置白名单
第二步:点击接口测试,配置好你要测试的IP白名单(api服务器IP),接下来操作那一列有一个【开始测试】按钮,点击获取测试码(最好一个个接口测试)。
第三步: 添加测试代码(thinkphp框架,Wlc类请看文章最后)
1、testcase01-实名认证接口(认证成功),testcase02-实名认证接口(认证中),testcase03-实名认证接口(认证失败)
测试地址:https://wlc.nppa.gov.cn/test/authentication/check/测试码
// 测试防成谜(接口测试)
public function checkTest()
{
$appid = '';
$bizId = ;
$key = "";
$wlc = new Wlc($appid, $key, $bizId);
//认证成功
$body = [
"ai" => '1000023000000007',
"name" => '某一七',
"idNum" => '110000190101030010',
];
$res = $wlc->setBody($body)->check();
print_r($res);
}
说明:参数按照传就行说明文档,testcase03的参数随便改错一个即可
2、testcase04-实名认证结果查询接口(认证成功),testcase05-实名认证结果查询接口(认证中),testcase06-实名认证结果查询接口(认证失败)
测试地址:https://wlc.nppa.gov.cn/test/authentication/query/测试码?
// 测试防成谜(接口测试)
public function queryTest()
{
$appid = '';
$bizId = ;
$key = "";
$wlc = new Wlc($appid, $key, $bizId);
//认证成功
$body = [
"ai" => '300000000000000002',
];
$res = $wlc->setParams($body)->query();
print_r($res);
}
说明:参数按照传就行说明文档,testcase06的参数随便改错一个即可
3、 testcase07-游戏用户行为数据上报接口(游客模式),testcase08-游戏用户行为数据上报接口(已认证)
测试地址:https://wlc.nppa.gov.cn/test/collection/loginout/测试码
游客模式:
// 测试防成谜(接口测试)
public function loginoutTest()
{
$appid = '';
$bizId = ;
$key = "";
$wlc = new Wlc($appid, $key, $bizId);
//认证成功 (游客模式)
$body =[
'collections'=>[
[
'no'=>1,
'si'=>'95edkzei5exh47pk0z2twm6zpielesrd',
'bt'=>0,
'ot'=>time(),
'ct'=>2,
'di'=>'ecvndx6r6xfwofmufs3lbimcr639r33t',
]
],
];
$res = $wlc->setBody($body)->loginout();
print_r($res);
}
已认证模式:
// 测试防成谜(接口测试)
public function loginoutTest()
{
$appid = '';
$bizId = ;
$key = "";
$wlc = new Wlc($appid, $key, $bizId);
//认证用户测试上报
$presetlist = [
['pi'=>'1fffbjzos82bs9cnyj1dna7d6d29zg4esnh99u'],
['pi'=>'1fffbkmd9ebtwi7u7f4oswm9li6twjydqs7qjv'],
];
$preset = $presetlist[mt_rand(0,count($presetlist)-1)];
$pi = $preset['pi'];
$body =[
'collections'=>[
[
'no'=>1,
'si'=>'95edkzei5exh47pk0z2twm6zpielesrd',
'bt'=>0,
'ot'=>time(),
'ct'=>0,
'di'=>'ecvndx6r6xfwofmufs3lbimcr639r33t',
'pi'=>$pi
]
],
];
$res = $wlc->setBody($body)->loginout();
print_r($res);
}
第四步:调试系统返回错误码
附录: 响应参数
字段 类型 名称 字段说明
errcode Int 状态码 状态码
errmsg String 状态描述 状态描述
data Object 响应对象 响应结果
data.result Object 响应结果对象 响应结果内容
data.result.status Int 实名认证结果 认证结果 0:认证成功 1:认证中 2:认证失败
data.result.pi String 用户唯一标识 已通过实名认证用户的唯一标识
接口返回状态码
状态码 状态描述 状态说明
0 OK 请求成功
1001 SYS ERROR 系统错误
1002 SYS REQ RESOURCE NOT EXIST 接口请求的资源不存在
1003 SYS REQ METHOD ERROR 接口请求方式错误
1004 SYS REQ HEADER MISS ERROR 接口请求核心参数缺失
1005 SYS REQ IP ERROR 接口请求IP地址非法
1006 SYS REQ BUSY ERROR 接口请求超出流量限制
1007 SYS REQ EXPIRE ERROR 接口请求过期
1008 SYS REQ PARTNER ERROR 接口请求方身份非法
1009 SYS REQ PARTNER AUTH DISABLE 接口请求方权限未启用
1010 SYS REQ AUTH ERROR 接口请求方无该接口权限
1011 SYS REQ PARTNER AUTH ERROR 接口请求方身份核验错误
1012 SYS REQ PARAM CHECK ERROR 接口请求报文核验失败
实名认证业务异常
2001 BUS AUTH IDNUM ILLEGAL 身份证号格式校验失败
2002 BUS AUTH RESOURCE LIMIT 实名认证条目已达上限
2003 BUS AUTH CODE NO AUTH RECODE 无该编码提交的实名认证记录
2004 BUS AUTH CODE ALREADY IN USE 编码已经被占用
游戏用户行为数据上报业务异常
3001 BUS COLL PARTIAL ERROR 行为数据部分上报失败
3002 BUS COLL BEHAVIOR NULL ERROR 行为数据为空
3003 BUS COLL OVER LIMIT COUNT 行为数据超出条目数量限制
3004 BUS COLL NO INVALID 行为数据编码错误
3005 BUS COLL BEHAVIOR TIME ERROR 行为发生时间错误
3006 BUS COLL PLAYER MODE INVALID 用户类型无效
3007 BUS COLL BEHAVIOR MODE INVALID 行为类型无效
3008 BUS COLL PLAYERID MISS 缺失PI(用户唯一标识)值
3009 BUS COLL DEVICEID MISS 缺失DI(设备标识)值 3
010 BUS COLL PLAYERID INVALID PI (用户唯一标识)值无效
Wlc类:(里面的地址都是正式地址)
<?php
namespace app\extend\wlc;
use app\extend\wlc\AESGCM;
class Wlc
{
public $app_id;
public $secret_key;
public $biz_id;
public $headers;
public $body;
public $params = [];
public function __construct($app_id, $secret_key, $biz_id)
{
$this->app_id = $app_id;
$this->secret_key = $secret_key;
$this->biz_id = $biz_id;
$time = $this->mtime();
$this->headers = [
"appId" => $this->app_id,
"bizId" => $this->biz_id,
"timestamps" => "$time",
];
return $this;
}
/**
* 获取毫秒
* @return float
*/
protected function mtime()
{
list($msec, $sec) = explode(' ', microtime());
$mtime = round(round($sec . substr($msec, 2, 3)));
return $mtime;
}
/**
* 加密请求体
* @param $text
* @return string
*/
protected function encrypt($text)
{
$key = hex2bin($this->secret_key);
$cipher = "aes-128-gcm";
$iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($cipher));
//php7.1以上可直接使用以下代码
if (version_compare(PHP_VERSION, '7.1.0') >= 0) {
$encrypt = openssl_encrypt($text, $cipher, $key, OPENSSL_RAW_DATA, $iv, $tag);
return base64_encode($iv . $encrypt . $tag);
}
//php5.6-7.0使用以下代码
list($encrypt, $tag) = AESGCM::encrypt($key, $iv, $text);
$str = bin2hex($iv) . bin2hex($encrypt) . bin2hex($tag);
return base64_encode(hex2bin($str));
}
/**
* 签名
* @param $body
* @return string
*/
protected function sign($body)
{
$data = array_merge($this->headers, $this->params);
ksort($data);
$sign_str = '';
foreach ($data as $k => $v) {
$sign_str .= "{$k}{$v}";
}
$sign_str = $this->secret_key . $sign_str . $body;
$sign = hash("sha256", $sign_str);
return $sign;
}
/**
* 发送请求
* @param $url
* @param $method
* @param $headers
* @param $body
* @return mixed
*/
protected function request($url, $method, $headers, $body)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, strtoupper($method));
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_TIMEOUT, 5);
$response = curl_exec($ch);
curl_close($ch);
unset($ch);
return json_decode($response, true);
}
/**
* 设置url 请求参数
* @param $params
* @return $this
*/
public function setParams($params)
{
$this->params = $params;
return $this;
}
/**
* 设置请求体
* @param $body
* @return $this
*/
public function setBody($body)
{
$this->body = $body;
return $this;
}
public function check()
{
$url = "https://api.wlc.nppa.gov.cn/idcard/authentication/check";
//加密请求体
$body = json_encode([
"data" => $this->encrypt(json_encode($this->body, JSON_UNESCAPED_UNICODE)),
]);
//签名
$sign = $this->sign($body);
$headers[] = "sign:$sign";
$headers[] = "Content-Type:application/json; charset=utf-8";
foreach ($this->headers as $k => $v) {
$headers[] = "{$k}:{$v}";
}
return $this->request($url, "POST", $headers, $body);
}
public function query()
{
$url = "http://api2.wlc.nppa.gov.cn/idcard/authentication/query";
//设置url参数
$params = '';
if (!empty($this->params)) {
$params = http_build_query($this->params);
$url .= "?$params";
}
$body = '';
$sign = $this->sign($body);
$headers[] = "sign:$sign";
foreach ($this->headers as $k => $v) {
$headers[] = "{$k}:{$v}";
}
return $this->request($url, "GET", $headers, $body);
}
public function loginout()
{
$url = "http://api2.wlc.nppa.gov.cn/behavior/collection/loginout";
//加密请求体
$body = json_encode([
"data" => $this->encrypt(json_encode($this->body, JSON_UNESCAPED_UNICODE)),
]);
//签名
$sign = $this->sign($body);
$headers[] = "sign:$sign";
$headers[] = "Content-Type:application/json; charset=utf-8";
foreach ($this->headers as $k => $v) {
$headers[] = "{$k}:{$v}";
}
return $this->request($url, "POST", $headers, $body);
}
}
AESGCM类:
<?php
/*
* https://github.com/Spomky-Labs/php-aes-gcm
* 从以上gitub项目提取的单文件
*/
namespace app\extend\wlc;
class AESGCM
{
/**
* @param string $K Key encryption key
* @param string $IV Initialization vector
* @param null|string $P Data to encrypt (null for authentication)
* @param null|string $A Additional Authentication Data
* @param int $tag_length Tag length
*
* @return array
*/
public static function encrypt($K, $IV, $P = null, $A = null, $tag_length = 128)
{
$key_length = mb_strlen($K, '8bit') * 8;
if (version_compare(PHP_VERSION, '7.1.0RC5') >= 0 && null !== $P) {
return self::encryptWithPHP71($K, $key_length, $IV, $P, $A, $tag_length);
} elseif (class_exists('\Crypto\Cipher')) {
return self::encryptWithCryptoExtension($K, $key_length, $IV, $P, $A, $tag_length);
}
return self::encryptWithPHP($K, $key_length, $IV, $P, $A, $tag_length);
}
/**
* This method will append the tag at the end of the ciphertext.
*
* @param string $K Key encryption key
* @param string $IV Initialization vector
* @param null|string $P Data to encrypt (null for authentication)
* @param null|string $A Additional Authentication Data
* @param int $tag_length Tag length
*
* @return string
*/
public static function encryptAndAppendTag($K, $IV, $P = null, $A = null, $tag_length = 128)
{
return implode(self::encrypt($K, $IV, $P, $A, $tag_length));
}
/**
* @param string $K Key encryption key
* @param string $key_length Key length
* @param string $IV Initialization vector
* @param null|string $P Data to encrypt (null for authentication)
* @param null|string $A Additional Authentication Data
* @param int $tag_length Tag length
*
* @return array
*/
private static function encryptWithPHP71($K, $key_length, $IV, $P = null, $A = null, $tag_length = 128)
{
$mode = 'aes-'.($key_length).'-gcm';
$T = null;
$C = openssl_encrypt($P, $mode, $K, OPENSSL_RAW_DATA, $IV, $T, $A, $tag_length / 8);
return [$C, $T];
}
/**
* @param string $K Key encryption key
* @param string $key_length Key length
* @param string $IV Initialization vector
* @param null|string $P Data to encrypt (null for authentication)
* @param null|string $A Additional Authentication Data
* @param int $tag_length Tag length
*
* @return array
*/
private static function encryptWithPHP($K, $key_length, $IV, $P = null, $A = null, $tag_length = 128)
{
list($J0, $v, $a_len_padding, $H) = self::common($K, $key_length, $IV, $A);
$C = self::getGCTR($K, $key_length, self::getInc(32, $J0), $P);
$u = self::calcVector($C);
$c_len_padding = self::addPadding($C);
$S = self::getHash($H, $A.str_pad('', $v / 8, "\0").$C.str_pad('', $u / 8, "\0").$a_len_padding.$c_len_padding);
$T = self::getMSB($tag_length, self::getGCTR($K, $key_length, $J0, $S));
return [$C, $T];
}
/**
* @param string $K Key encryption key
* @param string $key_length Key length
* @param string $IV Initialization vector
* @param null|string $P Data to encrypt (null for authentication)
* @param null|string $A Additional Authentication Data
* @param int $tag_length Tag length
*
* @return array
*/
private static function encryptWithCryptoExtension($K, $key_length, $IV, $P = null, $A = null, $tag_length = 128)
{
$cipher = \Crypto\Cipher::aes(\Crypto\Cipher::MODE_GCM, $key_length);
$cipher->setAAD($A);
$cipher->setTagLength($tag_length / 8);
$C = $cipher->encrypt($P, $K, $IV);
$T = $cipher->getTag();
return [$C, $T];
}
/**
* @param string $K Key encryption key
* @param string $IV Initialization vector
* @param string|null $C Data to encrypt (null for authentication)
* @param string|null $A Additional Authentication Data
* @param string $T Tag
*
* @return string
*/
public static function decrypt($K, $IV, $C, $A, $T)
{
$key_length = mb_strlen($K, '8bit') * 8;
$tag_length = self::getLength($T);
if (version_compare(PHP_VERSION, '7.1.0RC5') >= 0 && null !== $C) {
return self::decryptWithPHP71($K, $key_length, $IV, $C, $A, $T);
} elseif (class_exists('\Crypto\Cipher')) {
return self::decryptWithCryptoExtension($K, $key_length, $IV, $C, $A, $T, $tag_length);
}
return self::decryptWithPHP($K, $key_length, $IV, $C, $A, $T, $tag_length);
}
/**
* This method should be used if the tag is appended at the end of the ciphertext.
* It is used by some AES GCM implementations such as the Java one.
*
* @param string $K Key encryption key
* @param string $IV Initialization vector
* @param string|null $Ciphertext Data to encrypt (null for authentication)
* @param string|null $A Additional Authentication Data
* @param int $tag_length Tag length
*
* @return string
*
* @see self::encryptAndAppendTag
*/
public static function decryptWithAppendedTag($K, $IV, $Ciphertext = null, $A = null, $tag_length = 128)
{
$tag_length_in_bits = $tag_length / 8;
$C = mb_substr($Ciphertext, 0, -$tag_length_in_bits, '8bit');
$T = mb_substr($Ciphertext, -$tag_length_in_bits, null, '8bit');
return self::decrypt($K, $IV, $C, $A, $T);
}
/**
* @param string $K Key encryption key
* @param string $key_length Key length
* @param string $IV Initialization vector
* @param string|null $C Data to encrypt (null for authentication)
* @param string|null $A Additional Authentication Data
* @param string $T Tag
*
* @return string
*/
private static function decryptWithPHP71($K, $key_length, $IV, $C, $A, $T)
{
$mode = 'aes-'.($key_length).'-gcm';
$P = openssl_decrypt(null === $C ? '' : $C, $mode, $K, OPENSSL_RAW_DATA, $IV, $T, null === $A ? '' : $A);
return $P;
}
/**
* @param string $K Key encryption key
* @param string $key_length Key length
* @param string $IV Initialization vector
* @param string|null $C Data to encrypt (null for authentication)
* @param string|null $A Additional Authentication Data
* @param string $T Tag
* @param int $tag_length Tag length
*
* @return string
*/
private static function decryptWithPHP($K, $key_length, $IV, $C, $A, $T, $tag_length = 128)
{
list($J0, $v, $a_len_padding, $H) = self::common($K, $key_length, $IV, $A);
$P = self::getGCTR($K, $key_length, self::getInc(32, $J0), $C);
$u = self::calcVector($C);
$c_len_padding = self::addPadding($C);
$S = self::getHash($H, $A.str_pad('', $v / 8, "\0").$C.str_pad('', $u / 8, "\0").$a_len_padding.$c_len_padding);
$T1 = self::getMSB($tag_length, self::getGCTR($K, $key_length, $J0, $S));
return $P;
}
/**
* @param string $K Key encryption key
* @param string $key_length Key length
* @param string $IV Initialization vector
* @param string|null $C Data to encrypt (null for authentication)
* @param string|null $A Additional Authentication Data
* @param string $T Tag
* @param int $tag_length Tag length
*
* @return string
*/
private static function decryptWithCryptoExtension($K, $key_length, $IV, $C, $A, $T, $tag_length = 128)
{
$cipher = \Crypto\Cipher::aes(\Crypto\Cipher::MODE_GCM, $key_length);
$cipher->setTag($T);
$cipher->setAAD($A);
$cipher->setTagLength($tag_length / 8);
return $cipher->decrypt($C, $K, $IV);
}
/**
* @param $K
* @param $key_length
* @param $IV
* @param $A
*
* @return array
*/
private static function common($K, $key_length, $IV, $A)
{
$H = openssl_encrypt(str_repeat("\0", 16), 'aes-'.($key_length).'-ecb', $K, OPENSSL_NO_PADDING | OPENSSL_RAW_DATA); //---
$iv_len = self::getLength($IV);
if (96 === $iv_len) {
$J0 = $IV.pack('H*', '00000001');
} else {
$s = self::calcVector($IV);
$packed_iv_len = pack('N', $iv_len);
$iv_len_padding = str_pad($packed_iv_len, 8, "\0", STR_PAD_LEFT);
$hash_X = $IV.str_pad('', ($s + 64) / 8, "\0").$iv_len_padding;
$J0 = self::getHash($H, $hash_X);
}
$v = self::calcVector($A);
$a_len_padding = self::addPadding($A);
return [$J0, $v, $a_len_padding, $H];
}
/**
* @param string $value
*
* @return int
*/
private static function calcVector($value)
{
return (128 * ceil(self::getLength($value) / 128)) - self::getLength($value);
}
/**
* @param string $value
*
* @return string
*/
private static function addPadding($value)
{
return str_pad(pack('N', self::getLength($value)), 8, "\0", STR_PAD_LEFT);
}
/**
* @param string $x
*
* @return int
*/
private static function getLength($x)
{
return mb_strlen($x, '8bit') * 8;
}
/**
* @param int $num_bits
* @param int $x
*
* @return string
*/
private static function getMSB($num_bits, $x)
{
$num_bytes = $num_bits / 8;
return mb_substr($x, 0, $num_bytes, '8bit');
}
/**
* @param int $num_bits
* @param int $x
*
* @return string
*/
private static function getLSB($num_bits, $x)
{
$num_bytes = ($num_bits / 8);
return mb_substr($x, -$num_bytes, null, '8bit');
}
/**
* @param int $s_bits
* @param int $x
*
* @return string
*/
private static function getInc($s_bits, $x)
{
$lsb = self::getLSB($s_bits, $x);
$X = self::toUInt32Bits($lsb) + 1;
$res = self::getMSB(self::getLength($x) - $s_bits, $x).pack('N', $X);
return $res;
}
/**
* @param string $bin
*
* @return mixed
*/
private static function toUInt32Bits($bin)
{
list(, $h, $l) = unpack('n*', $bin);
return $l + ($h * 0x010000);
}
/**
* @param $X
* @param $Y
*
* @return string
*/
private static function getProduct($X, $Y)
{
$R = pack('H*', 'E1').str_pad('', 15, "\0");
$Z = str_pad('', 16, "\0");
$V = $Y;
$parts = str_split($X, 4);
$x = sprintf('%032b%032b%032b%032b', self::toUInt32Bits($parts[0]), self::toUInt32Bits($parts[1]), self::toUInt32Bits($parts[2]), self::toUInt32Bits($parts[3]));
$lsb_mask = "\1";
for ($i = 0; $i < 128; $i++) {
if ($x[$i]) {
$Z = self::getBitXor($Z, $V);
}
$lsb_8 = mb_substr($V, -1, null, '8bit');
if (ord($lsb_8 & $lsb_mask)) {
$V = self::getBitXor(self::shiftStringToRight($V), $R);
} else {
$V = self::shiftStringToRight($V);
}
}
return $Z;
}
/**
* @param string $input
*
* @return string
*/
private static function shiftStringToRight($input)
{
$width = 4;
$parts = array_map('self::toUInt32Bits', str_split($input, $width));
$runs = count($parts);
for ($i = $runs - 1; $i >= 0; $i--) {
if ($i) {
$lsb1 = $parts[$i - 1] & 0x00000001;
if ($lsb1) {
$parts[$i] = ($parts[$i] >> 1) | 0x80000000;
$parts[$i] = pack('N', $parts[$i]);
continue;
}
}
$parts[$i] = ($parts[$i] >> 1) & 0x7FFFFFFF;
$parts[$i] = pack('N', $parts[$i]);
}
$res = implode('', $parts);
return $res;
}
/**
* @param string $H
* @param string $X
*
* @return mixed
*/
private static function getHash($H, $X)
{
$Y = [];
$Y[0] = str_pad('', 16, "\0");
$num_blocks = (int) (mb_strlen($X, '8bit') / 16);
for ($i = 1; $i <= $num_blocks; $i++) {
$Y[$i] = self::getProduct(self::getBitXor($Y[$i - 1], mb_substr($X, ($i - 1) * 16, 16, '8bit')), $H);
}
return $Y[$num_blocks];
}
/**
* @param string $K
* @param int $key_length
* @param string $ICB
* @param string $X
*
* @return string
*/
private static function getGCTR($K, $key_length, $ICB, $X)
{
if (empty($X)) {
return '';
}
$n = (int) ceil(self::getLength($X) / 128);
$CB = [];
$Y = [];
$CB[1] = $ICB;
for ($i = 2; $i <= $n; $i++) {
$CB[$i] = self::getInc(32, $CB[$i - 1]);
}
$mode = 'aes-'.($key_length).'-ecb';
for ($i = 1; $i < $n; $i++) {
$C = openssl_encrypt($CB[$i], $mode, $K, OPENSSL_NO_PADDING | OPENSSL_RAW_DATA);
$Y[$i] = self::getBitXor(mb_substr($X, ($i - 1) * 16, 16, '8bit'), $C);
}
$Xn = mb_substr($X, ($n - 1) * 16, null, '8bit');
$C = openssl_encrypt($CB[$n], $mode, $K, OPENSSL_NO_PADDING | OPENSSL_RAW_DATA);
$Y[$n] = self::getBitXor($Xn, self::getMSB(self::getLength($Xn), $C));
return implode('', $Y);
}
/**
* @param string $o1
* @param string $o2
*
* @return string
*/
private static function getBitXor($o1, $o2)
{
$xorWidth = PHP_INT_SIZE;
$o1 = str_split($o1, $xorWidth);
$o2 = str_split($o2, $xorWidth);
$res = '';
$runs = count($o1);
for ($i = 0; $i < $runs; $i++) {
$res .= $o1[$i] ^ $o2[$i];
}
return $res;
}
}
特别说明:如果你复制过去调试不行,请下载样例自己再去封装一下就行了