以下操作确保已经申请了 腾讯的人脸核身服务 并拿到 appid 、Secret 与对应 license
官方文档:人脸核身 合作方后台上传身份信息-含 UI 集成方案-文档中心-腾讯云 (tencent.com)
uiapp插件地址DC-WBFaceServiceV2 - DCloud 插件市场
官方技术人员微信(vx:faceid001)
主要调用流程如下
第一步 :获取 accessToken
@Value("${tencent.appId}")
private String appId;
//这里是将参数配置在xml文件中 使用注解引用
@Value("${tencent.secret}")
private String secret;
private String grantType = "client_credential";
private String version = "1.0.0";
public String getAccessToken() {
String accessToken="";
//读取redis中有没有可以使用的 token。
if ( redisUtil.get("TXAccessToken")!=null){
accessToken = redisUtil.get("TXAccessToken").toString();
return accessToken;
}
try {
// 构建完整的URL
StringBuilder urlBuilder = new StringBuilder("https://kyc1.qcloud.com/api/oauth2/access_token?");
urlBuilder.append("appId=").append(appId);
urlBuilder.append("&secret=").append(secret);
urlBuilder.append("&grant_type=").append(grantType);
urlBuilder.append("&version=").append(version);
String s = HttpUtil.sendGet(urlBuilder.toString());
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(s);
String code = jsonNode.get("code").asText();
if ("0".equals(code)){
accessToken = jsonNode.get("access_token").asText();
//获取后存入redis缓存并设值时间为 1000秒
redisUtil.set("TXAccessToken",accessToken,1000);
}
} catch (Exception e) {
e.printStackTrace();
}
return accessToken;
}
第二步获取 Ticket
public String getApiTicket(String accessToken,String type) {
// accessToken是上面方法获取到的
//type 为获取的类型。
String tickets="";
if (type.equals("SIGN")){
if (redisUtil.get("TXSingTicket")!=null){
tickets = redisUtil.get("TXSingTicket").toString();
return tickets;
}
}
try {
// 构建完整的URL
StringBuilder urlBuilder = new StringBuilder("https://kyc1.qcloud.com/api/oauth2/api_ticket?");
urlBuilder.append("appId=").append(appId);
urlBuilder.append("&access_token=").append(accessToken);
urlBuilder.append("&type=").append(type);
if (type.equals("NONCE")){
LoginUser user =(LoginUser) SecurityUtils.getSubject().getPrincipal();
urlBuilder.append("&user_id=").append(user.getId());
}
urlBuilder.append("&version=").append("1.0.0");
String s = HttpUtil.sendGet(urlBuilder.toString());
ObjectMapper objectMapper = new ObjectMapper();
JsonNode jsonNode = objectMapper.readTree(s);
String code = jsonNode.get("code").asText();
if ("0".equals(code)){
JsonNode geocodesArray = jsonNode.get("tickets");
JsonNode jsonNode1 = geocodesArray.get(0);
tickets = jsonNode1.get("value").asText();
if (type.equals("SIGN")){
redisUtil.set("TXSingTicket",tickets,1000);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return tickets;
}
第三步获取sign签名
//这是 controller请求
这是前端生成的 32位 随机数 nonce type 是获取签名的类型
@GetMapping("/getSign")
public String sign(String nonce,String type) {
return tencentService.getSign(nonce,type);
}
@Override
public String getSign(String nonce,String type) {
//获取当前登陆人的id
LoginUser user =(LoginUser) SecurityUtils.getSubject().getPrincipal();
//调用上面的方法获取 token
String accessToken = getAccessToken();
//拿到token获取 Ticket 根据type 类型
String apiTicket = getApiTicket(accessToken,type);
List<String> values =new ArrayList<>(5);
values.add(user.getId());
values.add(apiTicket);
values.add("1.0.0");
values.add(appId);
values.add(nonce);
values.removeAll(Collections.singleton(null));// remove null
java.util.Collections.sort(values);
StringBuilder sb = new StringBuilder();
for (String s : values) {
sb.append(s);
}
System.out.println(sb +"sbbbbbbbbbbbbb");
return Hashing.sha1().hashString(sb, Charsets.UTF_8).toString().toUpperCase();
}
uiapp调用接口获取 faceId ,注意 :获取faceId 中 的 sign签名 生成时传递的 Ticket 是 SIGN类型
调用sdk 时生成 所需的sign签名 时传递的 ticket 是 NONCE类型。所以第二次调用后端接口传递的 type位 NONCE
const face = uni.requireNativePlugin('DC-WBFaceServiceV2'); //引用插件
enterH5FaceVerify() {
let q = {
nonce: this.nonce ,//32位随机数
type: "SIGN"
}
//后端接口
getSign(q).then(res1 => {
this.sign = res1
console.log(this.sign)
let Pdata = {
webankAppId: this.appId, //appid 与后端使用一致
orderNo: this.orderNo, //订单号,由合作方上送,每次唯一,不能超过32位
name: this.realName, //姓名
idNo: this.idCard, //证件号码
userId: this.userId, //用户 ID ,用户的唯一标识(不能带有特殊字符)
sourcePhotoStr: '', //比对源照片,注意:原始图片不能超过500KB,且必须为 JPG 或 PNG 格式;参数有值:使合作伙伴提供的比对源照片进行比对,必须注照片是正脸可信照片,照片质量由合作方保证;参数为空 :根据身份证号+姓名使用权威数据源比对
sourcePhotoType: '', //比对源照片类型,注意: 如合作方上送比对源则必传,使用权威数据源可不传;参数值为1:水纹正脸照;参数值为2:高清正脸照
version: '1.0.0', //默认参数值为:1.0.0
nonce: this.nonce,
sign: this.sign //签名:使用上文 生成的签名
}
console.log(Pdata, '签名获取成功')
uni.request({
url: 'https://kyc1.qcloud.com/api/server/getAdvFaceId',
method: 'POST',
data: Pdata,
success: (res) => {
console.log(res.data);
this.faceId = res.data.result
.faceId;
console.log(this.faceId, '开始调用插件');
let p = {
nonce: this.nonce,
type: "NONCE"
}
let F1 = ''
//再次调用 后端接口 获取调用sdk 所需的NONCE类型sign签名
getSign(p).then(res2 => {
F1 = res2
console.log(F1,'F1')
let qdata = {
userId: this.userId,
nonce: this.nonce,
sign: F1,
appId: this.appId,
orderNo: this.orderNo,
apiVersion: '1.0.0',
licence: this.licence,
faceType: '1',
compareType: '0',
faceId: this.faceId,
sdkConfig: {
//Android和iOS共有的配置参数
showSuccessPage: true, //是否展示成功页面
showFailurePage: true, //是否展示失败页面
recordVideo: true, //是否录制视频
playVoice: true, //是否播放语音提示
detectCloseEyes: true, //是否检测用户闭眼
theme: '1', //sdk皮肤设置,0黑色,1白色
//android独有的配置参数
isEnableLog: true, //是否打开刷脸native日志,请 release版本关闭!!!
//iOS独有的配置参数
windowLevel: '1', //sdk中拉起人脸活体识别界面中使用UIWindow时的windowLevel配置
manualCookie: true //是否由SDK内部处理sdk网络请求的cookie
}
}
console.log(qdata, '开始调用插件');
face.startAdvanceWbFaceVerifyService(
qdata,
result => {
if (result.res.success) {
this.sub()
}else{
console.log('失败')
uni.showToast({
title: '认证失败',
icon: 'error',
duration: 1000
})
}
}
);
})
},
fail(e) {
console.log(e);
},
complete() {}
});
}).catch(res => {
console.log(res)
})
},