最近项目上要使用腾讯云的人脸核身进行实名论证,使用的是增强版的,并开通了SDK对接和H5(非微信浏览器)对接两种方式。
H5(非微信浏览器)方式需要服务端先对接,传入姓名和身份证号后发起认证,返回一个认证链接给前端,前端打开WebView,认证完成后会自动跳转到回调页面更新认证结果。
服务端我使用的是PHP,贴下核心认证类的代码。
<?php
namespace third;
use GuzzleHttp\Client;
/**
* 腾讯云 人脸核身(增强版)
*/
class FaceVerify{
// 业务流程唯一标识,即 WBappid,可参考 获取 WBappid 指引在人脸核身控制台内申请
protected $app_id;
// WBappid 对应的密钥,申请 WBappid 时得到,可参考 获取 WBappid 指引在人脸核身控制台内申请
protected $secret;
// 授权类型,默认值为:client_credential(必须小写
private $grant_type = 'client_credential';
// 版本号,默认值为:1.0.0
private $version = '1.0.0';
// 获取AccessToken 接口链接
private $getAccessTokenUrl = 'https://kyc1.qcloud.com/api/oauth2/access_token';
// 获取SignTicket 接口链接
private $getSignTicketUrl = 'https://kyc1.qcloud.com/api/oauth2/api_ticket';
// 合作方后台上传身份信息
private $getH5FaceidUrl = 'https://kyc1.qcloud.com/api/server/getAdvFaceId';
// 认证完成回调跳转地址
protected $callbackUrl='';
/**
* 构造函数
* @param $appid 合作方appid
* @param $secret 合作方secret
* @param $callback_url 合作方回调地址
*/
function __construct($appid, $secret, $callback_url){
$this->app_id = $appid;
$this->secret = $secret;
$this->callbackUrl = $callback_url;
}
/**
* 合作方后台上传身份信息
* 并返回h5人脸核身链接
* https://cloud.tencent.com/document/product/1007/61073
* $orderNo 订单编码
* $name 姓名
* $idNo 身份证号
* $userId 用户ID
*/
public function getH5Faceverify($userId, $name, $idNo, $orderNo){
//$userId必须是字符串
$userId = $userId . "";
$post_url = $this->getH5FaceidUrl.'?orderNo='.$orderNo;
$sign_ticket = $this->getSignTicket();
$nonce = $this->getNonce(32);
//5个参数参与签名
$arr = [
$this->app_id,
$userId,
$nonce,
$this->version,
$sign_ticket
];
asort($arr, SORT_STRING);
$str = implode('', $arr);
$sign = sha1($str);
$post = [
'appId' => $this->app_id,
'orderNo' => $orderNo,
'name' => $name,
'idNo' => $idNo,
'userId' => $userId,
'version' => $this->version,
'sign' => $sign,
'nonce' => $nonce
];
$client = new Client();
$response = $client->request('POST', $post_url, [
'json' => $post,
])->getBody()->getContents();
$result = json_decode($response, true);
if ($result['code'] != 0){
return ['code' => 0, 'msg' => $result['msg']];
}
$optimalDomain = $result['result']['optimalDomain'];
$faceId = $result['result']['faceId'];
$nonce = $this->getNonce(32);
$url = $this->getH5Url($optimalDomain, $orderNo, $userId, $faceId, $sign_ticket, $nonce);
return ['code' => 1, 'msg' => '发起成功', 'url' => $url];
}
/**
* 生成签名并拼接人脸核身url
*/
private function getH5Url($optimalDomain, $orderNo, $userId, $faceId, $ticket, $nonce){
//7个参数参与签名
$arr = [
$this->app_id
,$orderNo
,$userId
,$this->version
,$faceId
,$ticket
,$nonce
];
asort($arr, SORT_STRING);
$str = implode('', $arr);
$sign = sha1($str);
$url = 'https://'.$optimalDomain.'/api/web/login?'
.'appId='.$this->app_id
.'&version='.$this->version
.'&nonce='.$nonce
.'&orderNo='.$orderNo
.'&faceId='.$faceId
.'&url='. urlencode($this->callbackUrl)
.'&userId='.$userId
.'&from=browser'
.'&sign='.$sign;
return $url;
}
/**
* 获取随机数
*/
private function getNonce($num){
$str="0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
$key = "";
for($i=0;$i<$num;$i++) {
$key .= $str[mt_rand(0,32)]; //生成php随机数
}
return $key;
}
/**
* 获取 SIGN ticket
* 文档: https://cloud.tencent.com/document/product/1007/57613
*/
private function getSignTicket(){
@mkdir(ROOT_PATH . "/runtime/faceverify/", 0777, true);
$file_path = RUNTIME_PATH. '/faceverify/sign_ticket.txt';
if(file_exists($file_path)){
$data = file_get_contents($file_path);
$data_arr = json_decode($data, true);
}
if (!isset($data_arr['expire_time']) || $data_arr['expire_time']<time()){
$url = $this->getSignTicketUrl
.'?app_id='.$this->app_id
.'&access_token='.$this->getAccessToken()
.'&type=SIGN&version='.$this->version;
$data = file_get_contents($url);
$data_arr = json_decode($data, true);
$data_arr = [
'expire_time' => time()+3600,
'sign_ticket' => $data_arr['tickets'][0]['value'],
];
file_put_contents($file_path, json_encode($data_arr, JSON_UNESCAPED_UNICODE));
}
return $data_arr['sign_ticket'];
}
/**
* 获取 access_token
* 文档: https://cloud.tencent.com/document/product/1007/57603
*/
private function getAccessToken(){
@mkdir(ROOT_PATH . "/runtime/faceverify/", 0777, true);
$file_path = RUNTIME_PATH. '/faceverify/access_token.txt';
if(file_exists($file_path)){
$data = file_get_contents($file_path);
$data_arr = json_decode($data, true);
}
if (!isset($data_arr['expire_time']) || $data_arr['expire_time']<time()){
$url = $this->getAccessTokenUrl
.'?app_id='.$this->app_id
.'&secret='.$this->secret
.'&grant_type='.$this->grant_type
.'&version='.$this->version;
$data = file_get_contents($url);
$data_arr = json_decode($data, true);
file_put_contents($file_path, json_encode([
'expire_time' => time()+7200,
'access_token' => $data_arr['access_token'],
], JSON_UNESCAPED_UNICODE));
}
return $data_arr['access_token'];
}
}
使用方法:
use \third\FaceVerify;
$app_id = ""; //开通服务的APPID
$secert = ""; //开通服务的APPID
$callback_url = "http://xxx.com/xxx/xx"; //回调地址
$verify = new FaceVerify($app_id, $secert, $callback_url);
$user_id = "1";
$name = ""; //姓名,要用真的
$idcard = ""; //身份证号,也要用真的,不然会发起失败
$order_no = date('YmdHis') . rand(1000, 9999);
$result = $verify->getH5Faceverify($user_id, $name, $idcard, $order_no);
发起成功的话会返回如下格式的数据
['code' => 1, 'msg' => '发起成功', 'url' = > 'https://....']
以上代码也大致适用于Plus版的人脸核身,参照官方文档改下接口链接和少部分参数即可。