文章目录
- 一、概述
- 二、实现流程
- 2.1. 获取获取 access_token
- 2.2. 获取 SIGN ticket
- 2.3. 生成签名
- 2.4. 上送身份信息
- 2.5. 获取 NONCE ticket
- 三、实战
- 3.1. 获取获取 access_token
- 3.2. 获取 SIGN ticket
- 3.3. 生成签名
- 3.4. 上送身份信息
- 3.5. 获取 NONCE ticket
- 四、开源地址
一、概述
人脸识别,使用官方API:腾讯云人脸核身之独立H5接入。接口官方返回code = 0 表示成功,其他code码值均为对应码值信息,详见错误码。
注意:
1.合作方上送身份信息的计算签名参数与启动人脸核身计算签名参数不一致,有部分区别。
2.wbappid = webankAppId = app_id
二、实现流程
2.1. 获取获取 access_token
文档: https://cloud.tencent.com/document/product/1007/37304
2.2. 获取 SIGN ticket
文档: https://cloud.tencent.com/document/product/1007/37305
2.3. 生成签名
文档: https://cloud.tencent.com/document/product/1007/35866
2.4. 上送身份信息
文档: https://cloud.tencent.com/document/product/1007/35866
2.5. 获取 NONCE ticket
文档: https://cloud.tencent.com/document/product/1007/37306
三、实战
3.1. 获取获取 access_token
app_id获取:https://cloud.tencent.com/document/product/1007/49634
secret获取:https://cloud.tencent.com/document/product/1007/49634
@Autowiredprivate RedisUtils redisUtils;@Value("${tencent-cloud.wbappid}")private String appId;@Value("${tencent-cloud.secret}")private String secret;/*** 获取 access_token* 文档: https://cloud.tencent.com/document/product/1007/37304** @return*/@Overridepublic String getAccessTokenTencent() {// 从redis中获取accessTokenTencentString 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_tokenaccessTokenTencent = jsonMap.get("access_token");// 过期时间 默认7200L 设置6800L提前重新获取redisUtils.set("accessTokenTencent", accessTokenTencent, 6800L);}log.info("返回有效accessToken,为:[{}]", accessTokenTencent);return accessTokenTencent;}
3.2. 获取 SIGN ticket
/*** 获取 SIGN ticket* 请求地址: http://localhost:9900/getSignTicketTencent* 文档: https://cloud.tencent.com/document/product/1007/37305** @param accessTokenTencent access_token* @return*/@Overridepublic String getSignTicketTencent(String accessTokenTencent) {// 从redis中获取nonceTicketTencentString 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;}
3.3. 生成签名
/*** 合作方上送身份信息计算签名* API: https://cloud.tencent.com/document/product/1007/35866** @param userId 用户唯一标识,同一个用户的 userId 请保持一致,我们会根据 userId 来做防重复点击优化* @param signTicket 合作伙伴服务端获取的 ticket,注意是 SIGN 类型* @return*/@Overridepublic String sign(String userId, String signTicket) {//为计算签名做准备List<String> list = new ArrayList<>();list.add(appId);list.add(userId);list.add(SignUtils.GenerateRandom32Number());list.add(TencentCloudConfig.VERSION);return SignUtils.getSign(list, signTicket);}
package com.gblfy.tencent.cloud.utils;import com.gblfy.tencent.cloud.result.GraceJSONResult;
import com.google.common.base.Charsets;
import com.google.common.hash.Hashing;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;import java.util.Collections;
import java.util.List;
import java.util.UUID;/*** Java 签名算法* 腾讯云文档: https://cloud.tencent.com/document/product/1007/37307** @author gblfy* @Date 2022-09-06**/
@Slf4j
@Component
public class SignUtils {//签名计算public static String getSign(List<String> values, String signTicket) {if (CollectionUtils.isEmpty(values)) {GraceJSONResult.errorMsg("签名计算 values is null");}// remove nullvalues.removeAll(Collections.singleton(null));values.add(signTicket);log.info("启动人脸核身签名排序前参数为:[{}]", values);java.util.Collections.sort(values);log.info("启动人脸核身签名排序后参数为:[{}]", values);StringBuilder sb = new StringBuilder();for (String s : values) {sb.append(s);}return Hashing.sha1().hashString(sb, Charsets.UTF_8).toString().toUpperCase();}//生成32位随机数public static String GenerateRandom32Number() {return UUID.randomUUID().toString().replace("-", "");}// public static void main(String[] args) {// System.out.println(UUID.randomUUID().toString().replace("-", "").length());// System.out.println(UUID.randomUUID().toString().replace("-", ""));// }
}
3.4. 上送身份信息
/*** 合作方后台上送身份信息** @param faceDetectUserVO 身份信息* @return*/@Overridepublic GraceJSONResult sendIdentityInfoUserInfo(FaceDetectUserVO faceDetectUserVO) {//获取accessTokenString accessToken = getAccessTokenTencent();//获取signTicketString signTicket = getSignTicketTencent(accessToken);//合作方上送计算签名String sign = sign(signTicket, faceDetectUserVO.getUserId());String orderNo = faceDetectUserVO.getOrderNo();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_FACEID_URL, orderNo);String jsonStr = HttpUtil.doPost(getFaceidUrl, JSON.toJSONString(param));log.info("返回报文;->{}", jsonStr);TXIdentityInfoDTO txIdentityInfoDTO = JSON.parseObject(jsonStr, TXIdentityInfoDTO.class);log.info("合作方上送身份信息接口返回:[{}]", txIdentityInfoDTO);return GraceJSONResult.ok(txIdentityInfoDTO);}
3.5. 获取 NONCE ticket
/*** 获取 NONCE ticket* 请求地址: http://localhost:9900/getNonceTicketTencent?userId=123456* 文档: https://cloud.tencent.com/document/product/1007/37306** @param userId 当前使用用户的唯一标识,需合作伙伴自行定义* @return*/@Overridepublic GraceJSONResult getNonceTicketTencent(String userId) {// 从redis中获取nonceTicketTencentString nonceTicketTencent = redisUtils.get("nonceTicketTencent");log.info("获取redis中的nonceTicketTencent,为:[{}]", nonceTicketTencent);// 获取access_tokenString accessTokenTencent = getAccessTokenTencent();String nonceTicketValue = null;if (StringUtils.isEmpty(nonceTicketTencent)) {String nonceTicketUrl = String.format(TencentCloudConfig.NONCE_TICKET_URL, appId, accessTokenTencent, userId);String jsonStr = HttpUtil.doGet(nonceTicketUrl, null);log.info("返回报文;->{}", jsonStr);TicketDTO ticketDTO = JSON.parseObject(jsonStr, TicketDTO.class);if (!"0".equals(ticketDTO.getCode())) {String msg = ticketDTO.getMsg();log.error("获取腾讯NonceTicket信息错误,code:{},msg:{}", ticketDTO.getCode(), msg);GraceJSONResult.errorMsg(msg);}/*** 正确响应示例:* {* "code": "0",* "msg": "请求成功",* "transactionTime": "20151022044027",* "tickets": [* {* "value": "ticket_string",* "expire_in": "120",* "expire_time": "20151022044027"* }* ]* }*/nonceTicketValue = ticketDTO.getTickets().get(0).getValue();// 过期时间 默认120L 设置100L提前重新获取redisUtils.set("nonceTicketTencent", nonceTicketValue, 100L);}return GraceJSONResult.ok(nonceTicketValue);}
四、开源地址
https://gitee.com/gblfy/tencent-cloud