import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.facedetection.faceVerify.entity.AccessTokenEntity;
import com.example.facedetection.faceVerify.entity.FaceidRsultEntity;
import com.example.facedetection.faceVerify.entity.SiginTicketEntity;
import com.google.common.base.Charsets;
import com.google.common.hash.Hashing;
import java.io.UnsupportedEncodingException;
import java.util.*;
/**
* @author kxz
* @title FaceVerifyPcUtil
* @Description: 人脸核身Pc端调用工具类(包含部分移动端共用方法)
* @date 2022/7/9
*/
public class FaceVerifyPcUtil {
private static String access_token_url = "https://miniprogram-kyc.tencentcloudapi.com/api/oauth2/access_token";
private static String api_ticket_url = "https://miniprogram-kyc.tencentcloudapi.com/api/oauth2/api_ticket";
private static String geth5faceid_url = "https://miniprogram-kyc.tencentcloudapi.com/api/server/h5/geth5faceid";
public static String accessToken = "WAA0f-dGGlQHTVClazkxtmW6FX_nRhpUB01QpWs5MbZluhUFn7WNPkTDcYYesaX-iJtc09MkkN152qd9It4AsQ8Mwg";
public static String signTicket = "bqpmxJrLtmJYk8BRN9RXhQPeaeWygLEf8QwpPHugBhBURaaLvBYAbXwJXU5NICK7";
public static void main(String[] args) throws UnsupportedEncodingException {
// 1.获取AccessToken
AccessTokenEntity accessTokenEntity = getAccessToken();
accessToken = accessTokenEntity.getAccessToken();
System.out.println("====accessToken:"+accessToken);
// 2.获取签名
SiginTicketEntity siginTicketEntity = FaceVerifyPcUtil.getSignTicket(FaceVerifyPcUtil.accessToken);
signTicket = siginTicketEntity.getTickets().get(0).getValue();
System.out.println("====signTicket:"+signTicket);
}
/**
* 1.获取AccessToken
* Access Token 必须缓存在磁盘,并定时刷新,且不能并发刷新,
* 建议每20分钟请求新的 Access Token,获取之后立即使用最新的 Access Token。
* 旧的只有一分钟的并存期。
*/
public static AccessTokenEntity getAccessToken(){
// 请求链接
String accessTokenUrl = access_token_url
+"?app_id=" + FaceConfig.APP_ID
+"&secret=" + FaceConfig.SECRET
+"&grant_type=" + FaceConfig.GRANT_TYPE
+"&version=" + FaceConfig.VERSION;
String accessTokenObj = HttpClientUtil.doGet(accessTokenUrl, "utf-8");
AccessTokenEntity accessToken = JSON.parseObject(accessTokenObj, AccessTokenEntity.class);
return accessToken;
}
/**
* 2.获取SignTicket
* SignTicket 必须缓存在磁盘,并定时刷新,且不能并发刷新,
* 建议每20分钟请求新的 SignTicket,获取之后立即使用最新的 SignTicket。
* 旧的只有一分钟的并存期。
*/
public static SiginTicketEntity getSignTicket(String accessToken){
// 请求链接
String accessTokenUrl = api_ticket_url
+"?app_id=" + FaceConfig.APP_ID
+"&access_token=" + accessToken
+"&type=" + FaceConfig.TYPE_SIGN
+"&version=" + FaceConfig.VERSION;
String signTicketObj = HttpClientUtil.doGet(accessTokenUrl, "utf-8");
SiginTicketEntity siginTicketEntity = JSON.parseObject(signTicketObj, SiginTicketEntity.class);
return siginTicketEntity;
}
// 3. 生成签名(用于geth5faceid接口)
public static String getSignTicketSign(String orderNo, String userId, String userName, String idCard, String signTicket){
// 获取SIGN ticket
List<String> list = new ArrayList<>();
// wbappid
list.add(FaceConfig.APP_ID);
// orderNo
list.add(orderNo);
// name
list.add(userName);
// idNo
list.add(idCard);
// userId
list.add(userId);
// version
list.add("1.0.0");
// 生成签名
String sign = sign(list, signTicket);
System.out.println("=======sign:"+sign);
return sign;
}
// 4. 调用geth5faceid接口
// API ticket 的 NONCE 类型,其有效期为120秒,且一次性有效,即每次启动 SDK 刷脸都要重新请求 NONCE ticket。
public static FaceidRsultEntity getH5faceid(String name, String idCard, String userId, String orderNo, String sign){
JSONObject jsonObject = new JSONObject();
jsonObject.put("webankAppId", FaceConfig.APP_ID);
jsonObject.put("name", name);
jsonObject.put("orderNo", orderNo);
jsonObject.put("idNo", idCard);
jsonObject.put("userId", userId);
jsonObject.put("version", FaceConfig.VERSION);
jsonObject.put("sign", sign);
System.out.println(jsonObject.toString());
String h5faceidResult = HttpClientUtil.doPost(geth5faceid_url+"?orderNo="+orderNo, jsonObject);
FaceidRsultEntity faceidRsultEntity = JSON.parseObject(h5faceidResult, FaceidRsultEntity.class);
return faceidRsultEntity;
}
// 5. 获取NONCE ticket
public static SiginTicketEntity getNonceTicket(String accessToken, String userId){
// 请求链接
String accessTokenUrl = api_ticket_url
+"?app_id=" + FaceConfig.APP_ID
+"&access_token=" + accessToken
+"&type=" + FaceConfig.TYPE_NONCE
+"&version=" + FaceConfig.VERSION
+"&user_id=" + userId;
String signTicketObj = HttpClientUtil.doGet(accessTokenUrl, "utf-8");
SiginTicketEntity siginTicketEntity = JSON.parseObject(signTicketObj, SiginTicketEntity.class);
return siginTicketEntity;
}
// 6. 获取H5人脸认证签名
public static String getNonceTicketSgin(String orderNo, String userId, String h5faceId, String nonceTicket, String nonce){
// 获取SIGN ticket
List<String> list = new ArrayList<>();
// wbappid
list.add(FaceConfig.APP_ID);
// version
list.add(FaceConfig.VERSION);
// orderNo
list.add(orderNo);
// userId
list.add(userId);
// h5faceId
list.add(h5faceId);
// nonce 随机数:32位随机串(字母+数字组成的随机数)
list.add(nonce);
// 生成签名
String sign = sign(list, nonceTicket);
System.out.println(sign);
return sign;
}
// 7. 获取“启动H5人脸合身”链接
public static String getH5Login(String optimalDomain, String userId, String orderNo, String h5faceId, String url, String signNonce, String nonce) {
String h5Url = "https://"+optimalDomain+"/api/pc/login"
+ "?webankAppId=" + FaceConfig.APP_ID
+ "&version=" + FaceConfig.VERSION
+ "&nonce="+nonce
+ "&orderNo=" + orderNo
+ "&h5faceId=" + h5faceId
+ "&url=" + url
+ "&userId=" + userId
+ "&sign=" + signNonce;
System.out.println("=========h5Url:"+h5Url);
return h5Url;
}
// 签名公共方法
protected static String sign(List<String> values, String ticket) { //values传ticket外的其他参数
if (values == null) {
throw new NullPointerException("values is null");
}
values.removeAll(Collections.singleton(null));// remove null
values.add(ticket);
java.util.Collections.sort(values);
StringBuilder sb = new StringBuilder();
for (String s : values) {
sb.append(s);
}
return Hashing.sha1().hashString(sb, Charsets.UTF_8).toString().toUpperCase();
}
// 获取任意长度随机字符串
public static String randomAlphanumeric(){
String str="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
Random random = new Random();
//指定字符串长度,拼接字符并toString
StringBuffer sb = new StringBuffer();
for (int i = 0; i < 32; i++) {
//获取指定长度的字符串中任意一个字符的索引值
int number = random.nextInt(str.length());
//根据索引值获取对应的字符
char charAt = str.charAt(number);
sb.append(charAt);
}
System.out.println("===========32位字符串:"+sb.toString());
return sb.toString();
}
}
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.example.facedetection.faceVerify.entity.FaceidRsultEntity;
import java.util.ArrayList;
import java.util.List;
/**
* @author kxz
* @title FaceVerifyModUtils
* @Description: 仅包含移动端独有方法,公用方法调用FaceVerifyPCUtil
* @date 2022/7/11
*/
public class FaceVerifyModUtils {
private static String ADVFACE_URL = "https://miniprogram-kyc.tencentcloudapi.com/api/server/getAdvFaceId";
// 1. 获取Sign ticket--与pc端共用,此处略
/**
* 2. 生成SIGN ticket签名
* @param userId 用户 ID ,用户的唯一标识(不要带有特殊字符)
* @param signTicket Sign ticket获取的值
* @param nonce 32位随机数
* @return
*/
public static String getSignTicketSign(String userId, String signTicket, String nonce){
// 获取SIGN ticket
List<String> list = new ArrayList<>();
// wbappid
list.add(FaceConfig.APP_ID);
// userId
list.add(userId);
// version
list.add("1.0.0");
// 32位随机数
list.add(nonce);
// 生成签名
String sign = FaceVerifyPcUtil.sign(list, signTicket);
System.out.println("=======sign:"+sign);
return sign;
}
/**
* 3. 调用AdvFaceId接口
* @param orderNo 订单号,字母/数字组成的字符串,每次(同一次人脸核身)唯一,不能超过32位
* @param name 姓名
* @param idCard 证件号码
* @param userId 用户 ID ,用户的唯一标识(不能带有特殊字符),需要跟生成签名的 userId 保持一致
* @param ticketSign 签名:使用上面生成的签名
* @param nonce 随机数(和上面签名随机数保持一致)
* @return
*/
public static FaceidRsultEntity getAdvFaceId(String orderNo, String name, String idCard, String userId, String ticketSign, String nonce){
JSONObject jsonObject = new JSONObject();
jsonObject.put("appId", FaceConfig.APP_ID);
jsonObject.put("orderNo", orderNo);
jsonObject.put("name", name);
jsonObject.put("idNo", idCard);
jsonObject.put("userId", userId);
jsonObject.put("version", FaceConfig.VERSION);
jsonObject.put("sign", ticketSign);
jsonObject.put("nonce", nonce);
// post请求
String h5faceidResult = HttpClientUtil.doPost(ADVFACE_URL+"?orderNo="+orderNo, jsonObject);
FaceidRsultEntity faceidRsultEntity = JSON.parseObject(h5faceidResult, FaceidRsultEntity.class);
return faceidRsultEntity;
}
// 4. 获取NonceTicket-使用pc端的,此处略
// 5. 生成Nonce签名
public static String getNonceTicketSign(String orderNo, String userId, String faceId, String noceTicketSign, String nonce){
// 获取SIGN ticket
List<String> list = new ArrayList<>();
// wbappid
list.add(FaceConfig.APP_ID);
// orderNo
list.add(orderNo);
// userId
list.add(userId);
// faceId
list.add(faceId);
// version
list.add("1.0.0");
// 32位随机数
list.add(nonce);
// 生成签名
String sign = FaceVerifyPcUtil.sign(list, noceTicketSign);
System.out.println("=======sign:"+sign);
return sign;
}
/**
* 6. 生成“启动H5人脸核身”链接
* @param optimalDomain 必填;使用getAdvFaceId接口返回的 optimalDomain 域名
* @param nonce 必填;随机数:32位随机串(字母 + 数字组成的随机数),需与Nonce签名保持一致
* @param orderNo 必填;订单号,字母/数字组成的字符串,每次唯一,此信息为本次人脸核身上送的信息,不能超过32位
* @param faceId 必填;getAdvFaceId接口返回的唯一标识
* @param url 必填;H5 人脸核身完成后回调的第三方 URL,需要第三方提供完整 URL 且做 URL Encode
* @param resultType 非必填;是否显示结果页面,参数值为“1”时直接跳转到 url 回调地址,null 或其他值跳转提供的结果页面
* @param userId 必填;用户 ID ,用户的唯一标识(不要带有特殊字符)
* @param noceSign 必填;签名:使用上面Nonce生成的签名
* @param from 必填;browser:表示在浏览器启动刷脸;App:表示在 App 里启动刷脸,默认值为 App;公众号属于浏览器
* @param redirectType 非必填;跳转模式,参数值为“1”时,刷脸页面使用 replace 方式跳转,不在浏览器 history 中留下记录;不传或其他值则正常跳转
* @return
*/
public static String getLoginUrl(String optimalDomain, String nonce, String orderNo, String faceId,
String url, String resultType, String userId, String noceSign, String from,
String redirectType){
StringBuilder sb = new StringBuilder("https://");
sb.append(optimalDomain).append("/api/web/login");
sb.append("?webankAppId=").append(FaceConfig.APP_ID);
sb.append("&version=").append(FaceConfig.VERSION);
sb.append("&nonce=").append(nonce);
sb.append("&orderNo=").append(orderNo);
sb.append("&faceId=").append(faceId);
sb.append("&url=").append(url);
sb.append("&resultType=").append(resultType);
sb.append("&userId=").append(userId);
sb.append("&sign=").append(noceSign);
sb.append("&from=").append(from);
sb.append("&redirectType=").append(redirectType);
System.out.println("=========h5Url:"+ sb);
return sb.toString();
}
}
付完整demo,开箱即用:https://download.csdn.net/download/just_you_java/86092683
参考文档: