光之使者 发表于 2024-6-9 13:22:56

AI 腾讯云人脸核身之独立H5接入

一、概述

人脸识别,利用官方API:腾讯云人脸核身之独立H5接入。接口官方返回code = 0 表现乐成,其他code码值均为对应码值信息,详见错误码。
注意:
1.合作方上送身份信息的计算署名参数与启动人脸核身计算署名参数不一致,有部门区别。
2.wbappid = webankAppId = app_id
二、合作方后台上送身份信息~实现流程

2.1. 前端入参

前端入参:客户身份证号、客户姓名、用户 ID (userId)、from(App || browser)
controller
    @Autowired
    private PCH5SendIdentityService pch5SendIdentityService;

    /**
   * 合作方后台上送身份信息 PC H5
   * 文档:https://cloud.tencent.com/document/product/1007/35893
   * <p>
   * 请求 URL:https://miniprogram-kyc.tencentcloudapi.com/api/server/h5/geth5faceid?orderNo=xxx
   * 请求方法:POST
   * 报文格式:Content-Type: application/json
   * </p>
   *
   * @param faceDetectUserVO 身份信息
   */
    @PostMapping("/sendH5IdentityInfoUserInfo")
    public TXH5IdentityInfoDTO sendH5IdentityInfoUserInfo(@RequestBody FaceDetectUserVO faceDetectUserVO) {
      return pch5SendIdentityService.sendH5IdentityInfoUserInfo(faceDetectUserVO);
    }
entity
@Data
@AllArgsConstructor
@NoArgsConstructor
public class FaceDetectUserVO {

    // https://cloud.tencent.com/document/product/1007/35893
    private String name;//姓名
    private String idNo;//证件号码
    private String userId;//用户 ID ,用户的唯一标识(不能带有特殊字符),需要跟生成签名的 userId 保持一致
    private String from;//来源 App || browser)
}
2.2. 后端固定参数

后端固定参数:wbappid = webankAppId = app_id(API中介绍命名差别,注意)、orderNo(可自定义随机生成不唯一)、userId(可自定义随机生成不唯一)、version
2.3. 获取 Access Token

https://cloud.tencent.com/document/product/1007/57603
/**
   * 获取 access_token
   * 文档: https://cloud.tencent.com/document/product/1007/37304
   *
   * @return
   */
    @Override
    public String getAccessTokenTencent() {

      // 从redis中获取accessTokenTencent
      String accessTokenTencent = redisUtils.get("accessTokenTencent");
      log.info("获取redis中的accessToken,为:[{}]", accessTokenTencent);

      if (StringUtils.isEmpty(accessTokenTencent)) {
            String accessTokenUrl = String.format(TencentCloudConfig.ACCESS_TOKEN_URL, appId, secret);
            String jsonStr = HttpUtil.doGet(accessTokenUrl, null);

            log.info("返回报文;->{}", jsonStr);
            Map<String, String> jsonMap = ConvertUtils.stringToMap(jsonStr);

            if (!"0".equals(jsonMap.get("code"))) {
                String msg = jsonMap.get("msg");
                log.error("获取腾讯token信息错误,code:{},msg:{}", jsonMap.get("code"), msg);
                GraceJSONResult.errorMsg(msg);
                /**
               * 错误响应示例:
               * {
               *   "code": "66660000",
               *   "msg": "请求参数异常",
               *   "bizSeqNo": "22090720001184453210262184859700",
               *   "transactionTime": "20220907102621",
               *   "success": false,
               *   "expire_in": 0
               * }
               */
            }
            /**
             * 正确响应示例:
             * {
             *"code":"0","msg":"请求成功",
             *"transactionTime":"20151022043831",
             *"access_token":"accessToken_string",
             *"expire_time":"20151022043831",
             *"expire_in":"7200"
             * }
             */
            // 获取 access_token
            accessTokenTencent = jsonMap.get("access_token");

            // 过期时间 默认7200L设置6800L提前重新获取
            redisUtils.set("accessTokenTencent", accessTokenTencent, 6800L);
      }

      log.info("返回有效accessToken,为:[{}]", accessTokenTencent);
      return accessTokenTencent;
    }

2.4. 获取 SIGN ticket

https://cloud.tencent.com/document/product/1007/57613
通过token获取signTicket
/**
   * 获取 SIGN ticket
   * 请求地址: http://localhost:9900/getSignTicketTencent
   * 文档: https://cloud.tencent.com/document/product/1007/37305
   *
   * @param accessTokenTencent access_token
   * @return
   */
    @Override
    public String getSignTicketTencent(String accessTokenTencent) {
      // 从redis中获取nonceTicketTencent
      String signTicketTencent = redisUtils.get("signTicketTencent");
      log.info("获取redis中的signTicketTencent,为:[{}]", signTicketTencent);

      String signTicketValue = null;
      if (StringUtils.isEmpty(signTicketTencent)) {
            String getSignTicketUrl = String.format(TencentCloudConfig.SIGN_TICKET_URL, appId, accessTokenTencent);
            String jsonStr = HttpUtil.doGet(getSignTicketUrl, null);
            log.info("返回报文;->{}", jsonStr);

            TicketDTO ticketDTO = JSON.parseObject(jsonStr, TicketDTO.class);
            if (!"0".equals(ticketDTO.getCode())) {
                String msg = ticketDTO.getMsg();
                log.error("获取腾讯signTicket信息错误,code:{},msg:{}", ticketDTO.getCode(), msg);
                GraceJSONResult.errorMsg(msg);
            }

            /**
             * 正确响应示例:
             * {
             *       "code": "0",
             *       "msg": "请求成功",
             *       "transactionTime": "20151022044027",
             *       "tickets": [
             *         {
             *            "value": "ticket_string",
             *            "expire_in": "3600",
             *            "expire_time": "20151022044027"
             *         }
             *   ]
             * }
             */
            signTicketValue = ticketDTO.getTickets().get(0).getValue();
            // 过期时间 默认3600L设置3200L提前重新获取
            redisUtils.set("signTicketTencent", signTicketValue, 3000L);
      }

      return signTicketValue;
    }

2.5. 生成署名

计算合作方上送身份信息署名,参数有:wbappid、orderNo、name、idNo、userId、version、signTicket
https://img-blog.csdnimg.cn/fe78e91894064f518feff044440f834a.png
计算署名
/**
   * PC 端 H5 接入 > 合作方上送身份信息计算签名
   * 文档地址:https://cloud.tencent.com/document/product/1007/35893
   *
   * @param faceDetectUserVO
   * @param signTicket
   * @return
   */
    public String signH5(FaceDetectUserVO faceDetectUserVO, String signTicket) {

      //为计算签名做准备
      //为计算签名做准备
      List<String> list = new ArrayList<>();
      list.add(appId);
      list.add(faceDetectUserVO.getOrderNo());
      list.add(faceDetectUserVO.getName());
      list.add(faceDetectUserVO.getIdNo());
      list.add(faceDetectUserVO.getUserId());
      list.add(TencentCloudConfig.VERSION);
      return SignUtils.getSign(list, signTicket);
    }
2.6. 合作方后台上送身份信息

/**
   * 合作方后台上送身份信息 PC H5
   * 文档:https://cloud.tencent.com/document/product/1007/35893
   * <p>
   * 请求 URL:https://miniprogram-kyc.tencentcloudapi.com/api/server/h5/geth5faceid?orderNo=xxx
   * 请求方法:POST
   * 报文格式:Content-Type: application/json
   * </p>
   *
   * @param faceDetectUserVO 身份信息
   * @return
   */
    @Override
    public TXH5IdentityInfoDTO sendH5IdentityInfoUserInfo(FaceDetectUserVO faceDetectUserVO) {
      //获取accessToken
      String accessToken = commonIdentityService.getAccessTokenTencent();
      //获取signTicket
      String signTicket = commonIdentityService.getSignTicketTencent(accessToken);
      //订单号
      String orderNo = SignUtils.GenerateRandom32Number(32);
      faceDetectUserVO.setOrderNo(orderNo);
      //合作方上送计算签名
      String sign = signH5(faceDetectUserVO, signTicket);

      Map<String, String> param = new HashMap<>(16);
      param.put("webankAppId", appId);
      param.put("orderNo", orderNo);
      param.put("name", faceDetectUserVO.getName());
      param.put("idNo", faceDetectUserVO.getIdNo());
      param.put("userId", faceDetectUserVO.getUserId());
      param.put("version", TencentCloudConfig.VERSION);
      param.put("sign", sign);

      log.debug("合作方上送身份信息参数有:[{}]", param);
      String getFaceidUrl = String.format(TencentCloudConfig.GET_H5_FACEID_URL, orderNo);
      String jsonStr = HttpUtil.doPost(getFaceidUrl, JSON.toJSONString(param));
      log.info("返回报文;->{}", jsonStr);

      TXH5IdentityInfoDTO txh5IdentityInfoDTO = JSON.parseObject(jsonStr, TXH5IdentityInfoDTO.class);
      log.info("合作方上送身份信息接口返回:[{}]", txh5IdentityInfoDTO);
      return txh5IdentityInfoDTO;
    }

三、启动H5人脸核身

3.1. 获取h5faceId

在合作方乐成上送身份信息后,可以获取到h5faceId
3.2. 获取nonce

(32位随机数)
3.3. 获取nonceTicket

获取nonceTicket(通过token & userId)
3.4. 计算启动署名

https://cloud.tencent.com/document/product/1007/61074
计算启动H5人脸核身署名,参数有:wbappid、orderNo、userId、version、h5faceId、nonce、nonceTicket
https://img-blog.csdnimg.cn/836a810403514d35bbb55210594d61ec.png
   /**
   * 启用 H5 人脸认证 人脸核身计算签名
   * 文档:https://cloud.tencent.com/document/product/1007/35894
   *
   * @param orderNo   订单号,字母/数字组成的字符串,本次人脸验证合作伙伴上送的订单号,唯一标识
   * @param userId      用户 ID ,用户的唯一标识(不要带有特殊字符)
   * @param nonceTicket 合作伙伴服务端实时获取的 tikcet,注意是 NONCE 类型
   * @param h5faceId    h5/geth5faceid 接口返回的唯一标识
   * @param nonce       随机数:32位随机串(字母+数字组成的随机数)
   * @return
   */
    private String faceSignH5(String orderNo, String userId, String nonceTicket, String h5faceId, String nonce) {

      //为计算签名做准备
      List<String> list = new ArrayList<>();
      list.add(appId);
      list.add(orderNo);
      list.add(userId);
      list.add(TencentCloudConfig.VERSION);
      list.add(h5faceId);
      list.add(nonce);
      String sign = SignUtils.getSign(list, nonceTicket);
      log.info("启动人脸核身返回签名为:[{}]", sign);
      return sign;
    }
3.5. 构建回调页面链接

将乐成拉起人脸核身验证通过后的回调页面链接配置至配置文件,同时对该链接进行encode编码
获取到全部拉起人脸核身所需参数后,向链接https://ida.webank.com/api/web/login拼接上参数:webankAppId、version、nonce、orderNo、h5faceId、url、sign、from、userId。例如:
https://ida.webank.com/api/web/login?webankAppId=%s&version=1.0.0&nonce=%s&orderNo=%s&h5faceId=%s&url&userId=%s&sign=%s&from=%s
接好后,直接将该链接返回前端去打开即可拉起人脸核身。请注意,该链接仅一次有效!!!

    /**
   * 构造人脸核身获取启动链接
   * 文档:https://cloud.tencent.com/document/product/1007/35894
   *
   * @param faceDetectUserVO
   * @return
   */
    @Override
    public GraceJSONResult startCheckFace(FaceDetectUserVO faceDetectUserVO) {
      //随机生成32位唯一用户ID和订单ID
      String userId = SignUtils.GenerateRandom32Number(32);
      String orderNo = SignUtils.GenerateRandom32Number(32);
      faceDetectUserVO.setOrderNo(orderNo);
      faceDetectUserVO.setUserId(userId);
      String requestUrl = "";
      try {

            //获取accessToken
            String accessToken = commonIdentityService.getAccessTokenTencent();
            //上送合作方用户信息
            TXH5IdentityInfoDTO txh5IdentityInfoDTO = sendH5IdentityInfoUserInfo(faceDetectUserVO);

            if (!"0".equals(txh5IdentityInfoDTO.getCode())) {
                String msg = txh5IdentityInfoDTO.getMsg();
                log.info("启动人脸核身--上送合作方用户信息异常,异常原因为:[{}]]", msg);
                GraceJSONResult.errorMsg(msg);
            }

            //获取h5/geth5faceid 接口返回的唯一标识
            String h5faceId = txh5IdentityInfoDTO.getResult().getH5faceId();

            //获取32位随机数
            String nonce = SignUtils.GenerateRandom32Number(32);

            //获取nonceTicket
            String nonceTicket = commonIdentityService.getNonceTicketTencent(accessToken, userId);

            //启动人脸核身计算签名
            String sign = faceSignH5(orderNo, userId, nonceTicket, h5faceId, nonce);

            //成功拉起人脸识别并识别成功或失败后的回调路径
            String oauthCallback = TencentCloudConfig.OAUTH_CALLBACK_URL;
            log.debug("人脸核身通过后的回调地址-拼接路径加密前:url = [{}]", oauthCallback);

            String oauthRedirectUrl = URLEncoder.encode(oauthCallback, "utf-8");
            log.debug("人脸核身通过后的回调地址-拼接路径加密后:url = [{}]", oauthRedirectUrl);

            /**
             * https://miniprogram-kyc.tencentcloudapi.com/api/pc/login?webankAppId=appId001
             * &version=1.0.0
             * &nonce=4bu6a5nv9t678m2t9je5819q46y9hf93
             * &orderNo=161709188560917432576916585
             * &h5faceId=wb04f10695c3651ce155fea7070b74c9
             * &url=https%3a%2f%2fcloud.tencent.com
             * &userId=23333333333333
             * &sign=5DD4184F4FB26B7B9F6DC3D7D2AB3319E5F7415F
             */
            requestUrl = String.format(TencentCloudConfig.REQUEST_URL, appId, nonce, orderNo, h5faceId, oauthRedirectUrl, userId, sign, faceDetectUserVO.getFrom());
      } catch (Exception e) {
            log.error("启动人脸核身异常,异常原因为:[{}]", e.getMessage());
      }
      log.info("启动人脸核身--请求路径为:[{}]]", requestUrl);
      return GraceJSONResult.ok(requestUrl);
    }
四、查询核身结果

4.1. 启动H5人脸核身

https://img-blog.csdnimg.cn/61cdd08d813c478a97f2d95c4039077a.png
https://img-blog.csdnimg.cn/8b947b78a7344952a5f4804b9f608a78.png
    /**
   * 前端获取结果验证签名
   * API:https://cloud.tencent.com/document/product/1007/61302
   *
   * @param orderNo 订单号,字母/数字组成的字符串,本次人脸核身合作伙伴上送的订单号,唯一标识
   * @return
   */
    private String getCheckSign(String orderNo) {
      //获取accessToken
      String accessToken = commonIdentityService.getAccessTokenTencent();

      //获取signTicket
      String signTicket = commonIdentityService.getSignTicketTencent(accessToken);
      List list = new ArrayList<>();
      list.add(appId);
      list.add(orderNo);
      list.add(TencentCloudConfig.VERSION);
      list.add(SignUtils.GenerateRandom32Number(32));
      String sign = SignUtils.getSign(list, signTicket);
      log.info("前端获取结果验证签名值为\"[{}]", sign);
      return sign;
    }

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页: [1]
查看完整版本: AI 腾讯云人脸核身之独立H5接入