人脸识别,使用官方API:腾讯云人脸核身之独立H5接入。接口官方返回code = 0 表示成功,其他code码值均为对应码值信息,详见错误码。
注意:
1.合作方上送身份信息的计算签名参数与启动人脸核身计算签名参数不一致,有部分区别。
2.wbappid = webankAppId = app_id
文档: https://cloud.tencent.com/document/product/1007/37304
文档: https://cloud.tencent.com/document/product/1007/37305
文档: https://cloud.tencent.com/document/product/1007/35866
文档: https://cloud.tencent.com/document/product/1007/35866
文档: https://cloud.tencent.com/document/product/1007/37306
app_id获取:https://cloud.tencent.com/document/product/1007/49634
secret获取:https://cloud.tencent.com/document/product/1007/49634
@Autowired
private 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
*/
@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;
}
/**
* 获取 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;
}
/**
* 合作方上送身份信息计算签名
* API: https://cloud.tencent.com/document/product/1007/35866
*
* @param userId 用户唯一标识,同一个用户的 userId 请保持一致,我们会根据 userId 来做防重复点击优化
* @param signTicket 合作伙伴服务端获取的 ticket,注意是 SIGN 类型
* @return
*/
@Override
public 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 null
values.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("-", ""));
// }
}
/**
* 合作方后台上送身份信息
*
* @param faceDetectUserVO 身份信息
* @return
*/
@Override
public GraceJSONResult sendIdentityInfoUserInfo(FaceDetectUserVO faceDetectUserVO) {
//获取accessToken
String accessToken = getAccessTokenTencent();
//获取signTicket
String 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);
}
/**
* 获取 NONCE ticket
* 请求地址: http://localhost:9900/getNonceTicketTencent?userId=123456
* 文档: https://cloud.tencent.com/document/product/1007/37306
*
* @param userId 当前使用用户的唯一标识,需合作伙伴自行定义
* @return
*/
@Override
public GraceJSONResult getNonceTicketTencent(String userId) {
// 从redis中获取nonceTicketTencent
String nonceTicketTencent = redisUtils.get("nonceTicketTencent");
log.info("获取redis中的nonceTicketTencent,为:[{}]", nonceTicketTencent);
// 获取access_token
String 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);
}