现在对接游戏,无论是登录还是支付都是要去对接防沉迷实名认证接口,但前期的话你要登录网络游戏防沉迷实名认证系统进行接口测试,$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);
}
第四步:调试系统返回错误码
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;
}
}
特别说明:如果你复制过去调试不行,请下载样例自己再去封装一下就行了