腾讯云人脸核身之独立H5接入
项目需求:要求在H5页面中接入第三方人脸识别,人脸识别校验通过后再进行后续业务流程。
需求调研:
经调研,阿里云目前不存在一个统一的接口实现“人证合一校验”,需要自己根据其api接口搭建业务场景。
阿里云"人证合一校验"文档:https://help.aliyun.com/document_detail/186171.html?spm=a2c4g.11186623.6.897.49a36d10QNAVAj
最终决定采用腾讯云“人脸核身”独立H5接入方式实现。
腾讯云“人脸核身”独立H5接入文档:https://cloud.tencent.com/document/product/1007/35883
腾讯云“人脸核身”实现步骤如下:
- 自助接入,申请申请WBappid,获取测试WBappid供开发调试使用;
- 获取 Access Token、获取 SIGN ticket、生成签名;
- 合作方后台上送身份信息;
- 获取 Access Token、获取 NONCE ticket、生成签名;
- 启动 H5 人脸核身;
- 获取 Access Token、获取 SIGN ticket、合作方后台生成签名;
- 服务端验证结果,调用身份认证查询接口;
- 实现人脸核身通过后续业务逻辑。
代码实现:
一、合作方后台上送身份信息
获取 Access Token、获取 SIGN ticket、生成签名
https://cloud.tencent.com/document/product/1007/35883
获取 Access Token
public function getToken() { $access_token = Cache::get('tencentyun_access_token_service'); // 如果缓存中没有access_token,则向微信服务器请求 if (empty($access_token)) { $url = 'https://idasc.webank.com/api/oauth2/access_token?app_id=' . $this->app_id . '&secret=' . $this->secret . '&grant_type=client_credential&version=1.0.0'; $str = curl_get($url); $result = !empty($str) ? json_decode($str, true) : []; if (!empty($result['access_token'])) { Cache::set('tencentyun_access_token_service', $result['access_token'], 6800); // 因为 API ticket 依赖于 Access Token,所以生命周期最长为 3600秒。为了简单方便,建议将 API ticket 与 Access Token 绑定,每20分钟定时刷新,原 API ticket 1 小时(3600秒)失效 $access_token = $result['access_token']; } } return $access_token; }
获取 SIGN ticket
public function getSignTicket($access_token) { // 换成中获取sign_ticket $sign_ticket = Cache::get('tencentyun_sign_ticket_service'); // 如果缓存中没有sign_ticket,则向微信服务器请求 if (empty($sign_ticket)) { $url = 'https://idasc.webank.com/api/oauth2/api_ticket?app_id=' . $this->app_id . '&access_token=' . $access_token. '&type=SIGN&version=1.0.0'; $str = curl_get($url); $result = !empty($str) ? json_decode($str, true) : []; if (!empty($result['tickets'][0]['value'])) { Cache::set('tencentyun_sign_ticket_service', $result['tickets'][0]['value'], 3000); // 因为 API ticket 依赖于 Access Token,所以生命周期最长为 3600秒。为了简单方便,建议将 API ticket 与 Access Token 绑定,每20分钟定时刷新,原 API ticket 1 小时(3600秒)失效 $sign_ticket = $result['tickets'][0]['value']; } } return $sign_ticket; }
生成签名
public function sign($orderNo='', $idNo='', $name='', $sign_ticket='', $userId='') { // 版本号 $version = '1.0.0'; $list[] = $this->app_id; $list[] = $orderNo; $list[] = $name; $list[] = $idNo; $list[] = $userId; $list[] = $version; $sign = $this->getSigh($list, $sign_ticket); return $sign; }
合作方后台上送身份信息
public function geth5faceid($userVo) { $tencentFaceidService = new TencentFaceidService(); // 获取accessToken $access_token = $tencentFaceidService->getToken(); // 获取signTicket $sign_ticket = $tencentFaceidService->getSignTicket($access_token); // 合作方上送计算签名 $sign = $tencentFaceidService->sign($userVo['orderNo'], $userVo['idNo'], $userVo['name'], $sign_ticket, $userVo['userId']); $userVo['sign'] = $sign; // 合作方上送身份信息 $url = 'https://idasc.webank.com/api/server/h5/geth5faceid'; $json = $tencentFaceidService->curlPost($url, $userVo, $timeOut = 8); $geth5faceid = json_decode($json, true); return $geth5faceid; }
二、启动 H5 人脸核身
https://cloud.tencent.com/document/product/1007/35884
获取 Access Token(同上)、获取 NONCE ticket
- 前置条件:请合作方确保 Access Token 已经正常获取。
- NONCE ticket 是合作方前端包含 App 和 H5 等生成签名鉴权参数之一,启动 H5 或 SDK 人脸核身。
- API ticket 的 NONCE 类型,其有效期为120秒,且一次性有效,即每次启动 SDK 刷脸都要重新请求 NONCE ticket。
public function getNonceTicket($access_token, $userId) { // 向微信服务器请求 $url = 'https://idasc.webank.com/api/oauth2/api_ticket?app_id=' . $this->app_id . '&access_token=' . $access_token. '&type=NONCE&version=1.0.0&user_id=' . $userId; $str = curl_get($url); $result = !empty($str) ? json_decode($str, true) : []; if (!empty($result['tickets'][0]['value'])) { $nonce_ticket = $result['tickets'][0]['value']; } return $nonce_ticket; }
启动人脸核身生成签名
public function faceSign($orderNo, $userId, $nonce_ticket, $h5faceId, $nonce) { $list[] = $this->app_id; $list[] = $orderNo; $list[] = $userId; $list[] = '1.0.0'; $list[] = $h5faceId; $list[] = $nonce; $sign = $this->getSigh($list, $nonce_ticket); return $sign; }
启动人脸核身,获取启动链接
public function startCheckFace() { $param = request()->param(); // 前端传参:客户身份证号、客户姓名、from(App || browser) // 校验参数 $validate = new \think\Validate([ 'idNo' => 'require|idCard', 'name' => 'require', 'url' => 'require', ]); $validate->message([ 'idNo.require' => '身份证号码不能为空', 'idNo.idCard' => '身份证号码不合法', 'name.require' => '姓名不能为空', 'url.require' => '跳转地址不能为空', ]); if (!$validate->check($param)) $this->error($validate->getError()); $userVo['idNo'] = $param['idNo']; $userVo['name'] = $param['name']; $from = 'App';// 默认APP $tencentFaceidService = new TencentFaceidService(); // 随机生成32位唯一用户ID和订单ID $userId = $tencentFaceidService->getUuid(); $orderNo = $tencentFaceidService->getUuid(); $userVo['webankAppId'] = config('Tencentyun.app_id'); $userVo['userId'] = $userId; $userVo['orderNo'] = $orderNo; $userVo['version'] = '1.0.0'; // 调起人脸核身链接 $requestUrl = ''; try { // 获取accessToken $access_token = $tencentFaceidService->getToken(); // 上送合作方用户信息 $geth5faceid = $this->geth5faceid($userVo); // 如果签名不合法,需要清空$access_token、$sign_ticket if ($geth5faceid['code'] == '400101') { Cache::set('tencentyun_access_token_service', null); Cache::set('tencentyun_sign_ticket_service', null); $this->error("签名不合法,请重试"); } if ($geth5faceid['code'] != 0) { $this->error($geth5faceid['msg']); } // 获取h5/geth5faceid 接口返回的唯一标识 $h5faceId = $geth5faceid['result']['h5faceId']; // 获取32位随机数 $nonce = $tencentFaceidService->getUuid(); // 获取nonceTicket $nonce_ticket = $tencentFaceidService->getNonceTicket($access_token, $userId); // 启动人脸核身计算签名 $sign = $tencentFaceidService->faceSign($orderNo, $userId, $nonce_ticket, $h5faceId, $nonce); // 成功拉起人脸识别并识别成功或失败后的回调路径,前端提供校验完成后回调地址,注意区分不同环境域名 (H5 人脸核身结果跳转) if (strpos($param['url'], '?')) {// 已经有参数 $path = config('share.BASE_URL') . '/h5' . $param['url'] . '&checked=1'; } else { $path = config('share.BASE_URL') . '/h5' . $param['url'] . '?checked=1'; } $url = urlencode($path); $requestUrl = "https://ida.webank.com/api/web/login?webankAppId=" . $userVo['webankAppId'] . "&version=" . $userVo['version'] . "&nonce=" . $nonce . "&orderNo=" . $orderNo . "&h5faceId=" . $h5faceId . "&url=" . $url . "&userId=" . $userId . "&sign=" . $sign . "&from=" . $from; } catch (Exception $e) { $this->error("启动人脸核身异常,异常原因如下:". $e->getMessage()); } $this->success($requestUrl); } // 生成uuid public function getUuid() { $chars = md5(uniqid(mt_rand(), true)); $uuid = substr ( $chars, 0, 8 ) . substr ( $chars, 8, 4 ) . substr ( $chars, 12, 4 ) . substr ( $chars, 16, 4 ) . substr ( $chars, 20, 12 ); return $uuid ; }
成功唤起示例

三、服务端验证结果
https://cloud.tencent.com/document/product/1007/35889
独立H5人脸核身提供了前端和服务端两种获取验证结果的方式,此处只阐述服务器端获取方式。
获取 Access Token、获取 SIGN ticket、合作方后台生成签名、服务端验证结果
public function serverCheckResult() { $param = request()->param(); // 校验参数 $validate = new \think\Validate([ 'orderNo' => 'require', ]); $validate->message([ 'orderNo.require' => '订单号不能为空', ]); if (!$validate->check($param)) $this->error($validate->getError()); $orderNo = $param['orderNo']; // app_id $app_id = config('Tencentyun.app_id'); $tencentFaceidService = new TencentFaceidService(); // 获取accessToken $access_token = $tencentFaceidService->getToken(); // 获取signTicket $sign_ticket = $tencentFaceidService->getSignTicket($access_token); // 获取32位随机数 $nonceStr = $tencentFaceidService->getUuid(); // 服务端验证结果签名 $sign = $tencentFaceidService->checkServerSign($orderNo, $nonceStr, $sign_ticket); // 合作方上送身份信息 $url = "https://idasc.webank.com/api/server/sync?app_id={$app_id}&nonce={$nonceStr}&order_no={$orderNo}&version=1.0.0&sign={$sign}&get_file=''"; $json = curl_get($url, $timeOut = 8); $json = json_decode($json, true); if ($json['code'] != 0) { $this->error($json['msg']); } $this->success($json['result']); } // 服务端验证结果合作方后台生成签名 public function checkServerSign($orderNo='', $nonceStr='', $sign_ticket='') { // 版本号 $version = '1.0.0'; $list[] = $this->app_id; $list[] = $orderNo; $list[] = $version; $list[] = $nonceStr; $sign = $this->getSigh($list, $sign_ticket); return $sign; }
四、人脸识别成功后续操作
……此处省略一万字……
注意:上线正式环境前需要替换正式WBappid。
java用户请参考链接:https://blog.csdn.net/HanSong_Ai/article/details/105760849

浙公网安备 33010602011771号