前言
本文主要针对手机app端调用人脸核身接口,主要讲解java开发部分,关于人脸核身的申请,接口地址之类的信息详见腾讯云文档:
腾讯云人脸核身接口文档
一.准备工作
实体类
返回参数
package com.sinosoft.springbootplus.agency.domain.entity;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* <pre>
* 人脸认证对象
* </pre>
*
* @author mc
* @date 2021-02-05
*/
@Data
@Accessors(chain = true)
@ApiModel(value = "FaceAuth对象", description = "人脸认证对象")
public class FaceAuth {
@ApiModelProperty(value = "业务流水号")
private String bizSeqNo;
@ApiModelProperty(value = "请求时间")
private String transactionTime;
@ApiModelProperty(value = "合作方订单号")
private String orderNo;
@ApiModelProperty(value = "人脸id")
private String faceId;
@ApiModelProperty(value = "是否成功 此字段false无意义")
private boolean success;
@ApiModelProperty(value = "订单号")
private String nonceStr;
@ApiModelProperty(value = "keyLicence")
private String keyLicence;
@ApiModelProperty(value = "签名")
private String sign;
@ApiModelProperty(value = "userId")
private String userId;
}
请求参数
package com.sinosoft.springbootplus.agency.param;
import com.sinosoft.springbootplus.mybatis.param.OrderQueryParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import javax.validation.constraints.NotBlank;
/**
* <pre>
* 人脸认证 参数对象
* </pre>
*
* @author mc
* @date 2021-02-05
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "FaceAuthQueryParam对象", description = "人脸认证参数")
public class FaceAuthParam extends OrderQueryParam {
private static final long serialVersionUID = 1L;
@ApiModelProperty(value = "姓名", required = true)
@NotBlank(message = "姓名不能为空")
private String name;
@ApiModelProperty(value = "身份证号", required = true)
@NotBlank(message = "身份证号不能为空")
private String idNo;
@ApiModelProperty(value = "用户标识")
private Long userId;
@ApiModelProperty(value = "NONCE ticket,有效期120秒")
private String ticket;
@ApiModelProperty(value = "32位随机数")
private String nonceStr;
}
配置信息
package com.sinosoft.springbootplus.agency.domain.config;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
/**
* <pre>
* 人脸认证配置文件
* </pre>
*
* @author mc
* @since 2021/4/16
*/
@Data
@Configuration
@ConfigurationProperties(prefix = "third-part.face")
public class FaceAuthProperties {
private String appId = "";
private String secretValue = "";
private String keyLicence = "";
private String accessTokenUrl = "https://idasc.webank.com/api/oauth2/access_token";
private String apiTicketUrl = "https://idasc.webank.com/api/oauth2/api_ticket";
private String signTicketUrl = "https://miniprogram-kyc.tencentcloudapi.com/api/oauth2/api_ticket";
private String faceUrl = "https://miniprogram-kyc.tencentcloudapi.com/api/server/getfaceid?orderNo=";
}
认证常量
package com.sinosoft.springbootplus.agency.domain.config;
/**
* <pre>
* 腾讯银行卡认证常量类
* </pre>
*
* @author mc
* @since 2021/4/16
*/
public interface TencentFaceAuthConstants {
/**
* 业务流程唯一标识,即 wbappid
*/
String APP_ID = "app_id";
/**
* wbappid 对应的密钥
*/
String SECRET = "secret";
/**
* 授权类型
*/
String GRANT_TYPE = "grant_type";
/**
* 授权类型 默认值
*/
String GRANT_TYPE_VALUE = "client_credential";
/**
* version
*/
String VERSION = "version";
/**
* version版本号
*/
String VERSION_VALUE = "1.0.0";
String TYPE = "type";
String NONCE = "NONCE";
}
用户信息常量
package com.sinosoft.springbootplus.agency.domain.constant;
/**
* <pre>
* 用户中心常量
* </pre>
*
* @author mc
* @date 2021-03-03
*/
public interface UserCenterConstant {
/**
* 返回编码 0
*/
String RESULT_CODE_ZERO = "0";
/**
* 返回编码 1
*/
String RESULT_CODE_ONE = "1";
/**
* 返回编码 200
*/
int RESULT_SUCCESS_CODE = 200;
/**
* 用户类型:个人用户
*/
Integer USER_TYPE_PERSON = 0;
/**
* 用户类型:法人用户
*/
Integer USER_TYPE_COMPANY = 1;
/**
* 数字2
*/
int NUM_TWO = 2;
// ================ 用户认证等级 ================
/**
* 用户中心 用户认证等级 未认证
*/
Integer UC_ZERO_AUTH = 0;
/**
* 用户中心 用户认证等级 手机号认证
*/
Integer UC_FIRST_AUTH = 1;
/**
* 用户中心 用户认证等级 身份证号认证
*/
Integer UC_SECOND_AUTH = 2;
/**
* 统一认证中心 用户认证等级 未认证
*/
Integer ID_ZERO_AUTH = 0;
/**
* 统一认证中心 用户认证等级 初级认证
*/
Integer ID_FIRST_AUTH = 1;
/**
* 统一认证中心 用户认证等级 中级认证
*/
Integer ID_SECOND_AUTH = 2;
// ================ 用户认证等级 ================
}
人脸认证枚举类
package com.sinosoft.springbootplus.agency.domain.config;
import com.sinosoft.springbootplus.common.enums.ThirdRepositoryEnum;
/**
* <pre>
* 人脸认证枚举类
* </pre>
*
* @author mc
* @since 2021/4/16
*/
public enum FaceAuthEnum implements ThirdRepositoryEnum {
/**
* 腾讯银行卡认证
*/
TENCENT_FACE_ACCESS_TOKEN("tencent_face_access_token_get", "人脸认证accessToken获取", "腾讯"),
TENCENT_FACE_API_TICKET("tencent_face_api_ticket_get", "人脸认证apiTicket获取", "腾讯"),
TENCENT_FACE_AUTH("tencent_face_auth", "人脸认证", "腾讯");
private String code;
private String name;
private String provider;
FaceAuthEnum(String code, String name, String provider) {
this.code = code;
this.name = name;
this.provider = provider;
}
@Override
public String getCode() {
return code;
}
@Override
public String getName() {
return name;
}
@Override
public String getProvider() {
return provider;
}
}
Controller
package com.sinosoft.springbootplus.agency.controller;
import com.alibaba.spring.util.ObjectUtils;
import com.sinosoft.springbootplus.agency.application.service.impl.FaceAuthServiceImpl;
import com.sinosoft.springbootplus.agency.domain.entity.FaceAuth;
import com.sinosoft.springbootplus.agency.param.FaceAuthParam;
import com.sinosoft.springbootplus.agency.utils.QRCodeUtil;
import com.sinosoft.springbootplus.common.api.ApiResult;
import com.sinosoft.springbootplus.common.exception.BusinessException;
import com.sinosoft.springbootplus.core.context.RequestContext;
import io.swagger.annotations.Api;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresUser;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
/**
* <pre>
* 人脸认证 API接口
* </pre>
*
* @author mc
* @date 2021-02-05
*/
@Slf4j
@RestController
@RequestMapping("/face")
@Api(tags="人脸核身 API")
public class FaceAuthController {
private FaceAuthServiceImpl faceAuthService;
public FaceAuthController(FaceAuthServiceImpl faceAuthService) {
this.faceAuthService = faceAuthService;
}
@PostMapping("/tencentFace")
@RequiresUser
public ApiResult<FaceAuth> authByFace(@Valid @RequestBody FaceAuthParam faceAuthParam) throws Exception {
return faceAuthService.authByFace(faceAuthParam);
}
}
ServiceImpl
package com.sinosoft.springbootplus.agency.application.service.impl;
import cn.hutool.core.util.IdUtil;
import com.sinosoft.springbootplus.agency.domain.constant.UserCenterConstant;
import com.sinosoft.springbootplus.agency.domain.entity.FaceAuth;
import com.sinosoft.springbootplus.agency.domain.repository.FaceAuthRepository;
import com.sinosoft.springbootplus.agency.param.FaceAuthParam;
import com.sinosoft.springbootplus.api.system.dto.UserOrgInfo;
import com.sinosoft.springbootplus.api.system.service.SystemOrgServiceApi;
import com.sinosoft.springbootplus.common.api.ApiResult;
import com.sinosoft.springbootplus.common.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
* <pre>
* 人脸认证 服务类
* </pre>
*
* @author mc
* @date 2021-02-05
*/
@Slf4j
@Service
public class FaceAuthServiceImpl {
private FaceAuthRepository faceAuthRepository;
private SystemOrgServiceApi systemOrgServiceApi;
public FaceAuthServiceImpl(FaceAuthRepository faceAuthRepository,SystemOrgServiceApi systemOrgServiceApi) {
this.faceAuthRepository = faceAuthRepository;
this.systemOrgServiceApi = systemOrgServiceApi;
}
/**
* 人脸识别上传身份信息
*
* @param faceAuthParam 人脸认证 查询参数对象
* @return ApiResult
* @throws Exception 异常
*/
@Transactional(rollbackFor = Exception.class)
public ApiResult<FaceAuth> authByFace(FaceAuthParam faceAuthParam) throws Exception {
// 根据用户id查询用户实名信息
//获取当前登录人的机构信息及机构等级
UserOrgInfo userOrg = systemOrgServiceApi.getUserOrg(faceAuthParam.getUserId());
String realName = userOrg.getPersonName();
String idCard = userOrg.getUserName();
if (StringUtils.isBlank(realName) || StringUtils.isBlank(idCard)) {
throw new BusinessException("请先进行实名认证再进行人脸认证");
}
faceAuthParam.setName(realName);
faceAuthParam.setIdNo(idCard);
ApiResult<String> accessTokenResult = faceAuthRepository.getAccessToken();
if (UserCenterConstant.RESULT_SUCCESS_CODE != accessTokenResult.getCode()) {
return ApiResult.fail(accessTokenResult.getMsg());
}
String accessToken = accessTokenResult.getData();
log.info("【人脸核身】获取accessToken为:{}", accessToken);
ApiResult<String> apiTicketResult = faceAuthRepository.getApiTicket(accessToken, faceAuthParam.getUserId().toString());
if (UserCenterConstant.RESULT_SUCCESS_CODE != apiTicketResult.getCode()) {
return ApiResult.fail(accessTokenResult.getMsg());
}
String apiTicket = apiTicketResult.getData();
log.info("【人脸核身】获取apiTicket为:{}", apiTicket);
faceAuthParam.setTicket(apiTicket);
String nonceStr = IdUtil.simpleUUID();
log.info("【人脸核身】获取nonceStr为:{}", nonceStr);
faceAuthParam.setNonceStr(nonceStr);
ApiResult<String> signTicketResult = faceAuthRepository.getSignTicket(accessToken);
if (UserCenterConstant.RESULT_SUCCESS_CODE != signTicketResult.getCode()) {
return ApiResult.fail(signTicketResult.getMsg());
}
String signTicket = signTicketResult.getData();
log.info("【人脸核身】获取signTicket为:{}", signTicket);
ApiResult<FaceAuth> apiResult = faceAuthRepository.authByFace(faceAuthParam,signTicket);
// 认证成功
// if (UserCenterConstant.RESULT_SUCCESS_CODE == apiResult.getCode()) {
// // 人脸识别临时表中添加用户已进行人脸核身身份记录
// faceAuthTmpDomain.addFaceAuthTmp(faceAuthParam);
// }
return apiResult;
}
}
FaceAuthRepository
package com.sinosoft.springbootplus.agency.domain.repository;
import com.sinosoft.springbootplus.agency.domain.entity.FaceAuth;
import com.sinosoft.springbootplus.agency.param.FaceAuthParam;
import com.sinosoft.springbootplus.common.api.ApiResult;
import org.springframework.stereotype.Repository;
import java.util.Map;
/**
* <pre>
* 人脸识别 仓储层
* </pre>
*
* @author mc
* @since 2021-01-26
*/
@Repository
public interface FaceAuthRepository {
/**
* 人脸核身获取 AccessToken
*
* @return accessToken字符串
* @throws Exception 获取异常
*/
ApiResult<String> getAccessToken() throws Exception;
/**
* 人脸核身获取 ApiTicket
*
* @param accessToken accessToken
* @param userId 用户id
* @return ApiTicket字符串
* @throws Exception 获取异常
*/
ApiResult<String> getApiTicket(String accessToken, String userId) throws Exception;
/**
* 人脸核身上传身份信息
*
* @param faceAuthParam 人脸认证 查询参数对象
* @return ApiResult
* @throws Exception 信息上传异常
*/
ApiResult<FaceAuth> authByFace(FaceAuthParam faceAuthParam,String signTicket) throws Exception;
/**
* 人脸核身获取
*
* @param accessToken accessToken
* @return ApiTicket字符串
* @throws Exception 获取异常
*/
ApiResult<String> getSignTicket(String accessToken) throws Exception;
}
TencentFaceAuthRepository
package com.sinosoft.springbootplus.agency.domain.repository.impl;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.google.common.hash.Hashing;
import com.sinosoft.springbootplus.agency.domain.config.FaceAuthEnum;
import com.sinosoft.springbootplus.agency.domain.config.FaceAuthProperties;
import com.sinosoft.springbootplus.agency.domain.config.TencentFaceAuthConstants;
import com.sinosoft.springbootplus.agency.domain.constant.UserCenterConstant;
import com.sinosoft.springbootplus.agency.domain.entity.FaceAuth;
import com.sinosoft.springbootplus.agency.domain.repository.FaceAuthRepository;
import com.sinosoft.springbootplus.agency.param.FaceAuthParam;
import com.sinosoft.springbootplus.agency.vo.AccessTokenResultVo;
import com.sinosoft.springbootplus.agency.vo.ApiTicketResultVo;
import com.sinosoft.springbootplus.agency.vo.ApiTicketVo;
import com.sinosoft.springbootplus.common.api.ApiResult;
import com.sinosoft.springbootplus.common.event.RepositoryExceptionEvent;
import com.sinosoft.springbootplus.util.EventPublisher;
import com.sinosoft.springbootplus.util.OkHttpRequestUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.Charsets;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Repository;
import javax.annotation.PostConstruct;
import java.io.IOException;
import java.util.*;
/**
* <pre>
* 腾讯人脸识别 仓储层
* </pre>
*
* @author mc
* @since 2021-01-26
*/
@Slf4j
@Repository
@EnableConfigurationProperties(value = FaceAuthProperties.class)
public class TencentFaceAuthRepository implements FaceAuthRepository, TencentFaceAuthConstants {
private FaceAuthProperties faceAuthProperties;
TencentFaceAuthRepository(FaceAuthProperties faceAuthProperties) {
this.faceAuthProperties = faceAuthProperties;
}
private static final Map<String, Object> GET_ACCESS_TOKEN_QUERY_MAP = new HashMap<>();
private static final Map<String, Object> GET_API_TICKET_BASE_MAP = new HashMap<>();
private static final String PUBLISH_FACE_AUTH_FORM = "header:{}, params:{}";
private static final Map<String, Object> HEADER_MAP = MapUtil.of("Content-Type", "application/json");
@Override
public ApiResult<String> getAccessToken() {
try {
String resultJson = OkHttpRequestUtils.doGet(faceAuthProperties.getAccessTokenUrl(), GET_ACCESS_TOKEN_QUERY_MAP);
log.debug("【人脸核身】获取accessToken返回数据:{}", resultJson);
if (StringUtils.isNotBlank(resultJson)) {
AccessTokenResultVo accessTokenResultVo = JSONUtil.toBean(resultJson, AccessTokenResultVo.class);
// 返回码不为0是 请求失败
if (UserCenterConstant.RESULT_CODE_ZERO.equals(accessTokenResultVo.getCode())) {
return ApiResult.ok(accessTokenResultVo.getAccessToken());
}
log.error("【人脸核身】获取accessToken接口失败,失败信息为;{}", accessTokenResultVo.getMsg());
} else {
log.error("【人脸核身】获取accessToken接口失败,返回信息为空");
publishFaceGetAccessTokenError(GET_ACCESS_TOKEN_QUERY_MAP, null);
}
return ApiResult.fail("人脸验证失败,请重试");
} catch (Exception e) {
log.error("【人脸核身】获取accessToken接口失败", e);
publishFaceGetAccessTokenError(GET_ACCESS_TOKEN_QUERY_MAP, e);
return ApiResult.fail("人脸验证失败,请重试");
}
}
@PostConstruct
private void initBaseMap() {
GET_ACCESS_TOKEN_QUERY_MAP.put(APP_ID, faceAuthProperties.getAppId());
GET_ACCESS_TOKEN_QUERY_MAP.put(SECRET, faceAuthProperties.getSecretValue());
GET_ACCESS_TOKEN_QUERY_MAP.put(GRANT_TYPE, GRANT_TYPE_VALUE);
GET_ACCESS_TOKEN_QUERY_MAP.put(VERSION, VERSION_VALUE);
GET_API_TICKET_BASE_MAP.put(APP_ID, faceAuthProperties.getAppId());
GET_API_TICKET_BASE_MAP.put(TYPE, NONCE);
GET_API_TICKET_BASE_MAP.put(VERSION, VERSION_VALUE);
}
@Override
public ApiResult<String> getApiTicket(String accessToken, String userId) {
Map<String, Object> apiTicketQueryMap = getApiTicketQueryMap(accessToken, userId);
try {
String resultJson = OkHttpRequestUtils.doGet(faceAuthProperties.getApiTicketUrl(), apiTicketQueryMap);
log.debug("【人脸核身】获取apiTicket接口返回数据:{}", resultJson);
if (StringUtils.isNotBlank(resultJson)) {
ApiTicketResultVo apiTicketResultVo = JSONUtil.toBean(resultJson, ApiTicketResultVo.class);
// 获取返回码
String code = apiTicketResultVo.getCode();
// 返回码不为0是 请求失败
if (!UserCenterConstant.RESULT_CODE_ZERO.equals(code)) {
// 获取返回信息
String msg = apiTicketResultVo.getMsg();
log.error("【人脸核身】获取apiTicket失败,错误码为:{},错误信息为:{}", code, msg);
return ApiResult.fail("人脸验证失败,请重试");
}
List<ApiTicketVo> tickets = apiTicketResultVo.getTickets();
return ApiResult.ok(tickets.get(0).getValue());
} else {
log.error("【人脸核身】获取apiTicket接口失败,返回信息为空");
publishFaceGetApiTicketError(apiTicketQueryMap, null);
return ApiResult.fail("人脸验证失败,请重试");
}
} catch (Exception e) {
log.error("【人脸核身】获取apiTicket接口失败", e);
publishFaceGetApiTicketError(apiTicketQueryMap, e);
return ApiResult.fail("人脸验证失败,请重试");
}
}
private Map<String, Object> getApiTicketQueryMap(String accessToken, String userId) {
// 请求参数
Map<String, Object> getApiTicketQueryMap = new HashMap<>(5);
getApiTicketQueryMap.put("access_token", accessToken);
getApiTicketQueryMap.put("user_id", userId);
getApiTicketQueryMap.putAll(GET_API_TICKET_BASE_MAP);
return getApiTicketQueryMap;
}
@Override
public ApiResult<FaceAuth> authByFace(FaceAuthParam faceAuthParam,String signTicket) {
String orderNo = faceAuthParam.getNonceStr();
log.info("【人脸核身】上传身份信息的订单号为【{}】", orderNo);
// 签名
ArrayList<String> list = new ArrayList<>();
list.add(faceAuthParam.getUserId().toString());
list.add(faceAuthProperties.getAppId());
list.add(faceAuthParam.getNonceStr());
list.add(VERSION_VALUE);
String sign = getSign(list,signTicket);
// 请求参数组装
String json = getAuthFaceParamMap(faceAuthParam, orderNo, sign);
log.debug("【人脸核身】请求认证接口请求数据为:{}", json);
try {
String result = OkHttpRequestUtils.doPost(faceAuthProperties.getFaceUrl()+orderNo, HEADER_MAP, json);
log.debug("【人脸核身】请求认证接口返回信息为:{}", result);
if (StringUtils.isBlank(result)) {
log.error("【人脸核身】请求认证接口失败,返回信息为空");
publishFaceAuthError(json, null);
return ApiResult.fail("人脸验证失败,请重试");
}
JSONObject jsonObject = JSONObject.parseObject(result);
// 获取返回码
String code = jsonObject.getString("code");
// 返回码不为0是 请求失败
if (!UserCenterConstant.RESULT_CODE_ZERO.equals(code)) {
String msg = jsonObject.getString("msg");
log.error("【人脸核身】获取apiTicket失败,错误码为:{},错误信息为:{}", code, msg);
return ApiResult.fail(msg);
}
FaceAuth faceAuth = jsonObject.getObject("result", FaceAuth.class);
log.info("【人脸核身】人脸验证后台上送信息成功,业务流水号为:{},时间为:{},合作方订单号为:{},人脸id为:{}", faceAuth.getBizSeqNo(),
faceAuth.getTransactionTime(), faceAuth.getOrderNo(), faceAuth.getFaceId());
faceAuth.setNonceStr(faceAuthParam.getNonceStr());
faceAuth.setKeyLicence(faceAuthProperties.getKeyLicence());
//nonceTicket生成的sign
ArrayList<String> nonceList = new ArrayList<>();
nonceList.add(faceAuthParam.getUserId().toString());
nonceList.add(faceAuthProperties.getAppId());
nonceList.add(faceAuthParam.getNonceStr());
nonceList.add(VERSION_VALUE);
String nonceSign = getSign(nonceList,faceAuthParam.getTicket());
faceAuth.setSign(sign);
faceAuth.setUserId(faceAuthParam.getUserId().toString());
return ApiResult.ok(faceAuth);
} catch (IOException e) {
log.error("【人脸核身】请求人脸验证后台信息上送接口失败", e);
publishFaceAuthError(json, e);
return ApiResult.fail("人脸验证失败,请重试");
}
}
@Override
public ApiResult<String> getSignTicket(String accessToken) throws Exception {
// 请求参数
Map<String, Object> getSignTicketQueryMap = new HashMap<>(5);
getSignTicketQueryMap.put("access_token", accessToken);
getSignTicketQueryMap.put("app_id", faceAuthProperties.getAppId());
getSignTicketQueryMap.put("type", "SIGN");
getSignTicketQueryMap.put("version", VERSION_VALUE);
try {
String resultJson = OkHttpRequestUtils.doGet(faceAuthProperties.getSignTicketUrl(), getSignTicketQueryMap);
log.debug("【人脸核身】获取signTicket接口返回数据:{}", resultJson);
if (StringUtils.isNotBlank(resultJson)) {
ApiTicketResultVo apiTicketResultVo = JSONUtil.toBean(resultJson, ApiTicketResultVo.class);
// 获取返回码
String code = apiTicketResultVo.getCode();
// 返回码不为0是 请求失败
if (!UserCenterConstant.RESULT_CODE_ZERO.equals(code)) {
// 获取返回信息
String msg = apiTicketResultVo.getMsg();
log.error("【人脸核身】获取signTicket失败,错误码为:{},错误信息为:{}", code, msg);
return ApiResult.fail("人脸验证失败,请重试");
}
List<ApiTicketVo> tickets = apiTicketResultVo.getTickets();
return ApiResult.ok(tickets.get(0).getValue());
} else {
log.error("【人脸核身】获取signTicket接口失败,返回信息为空");
publishFaceGetApiTicketError(getSignTicketQueryMap, null);
return ApiResult.fail("人脸验证失败,请重试");
}
} catch (Exception e) {
log.error("【人脸核身】获取signTicket接口失败", e);
publishFaceGetApiTicketError(getSignTicketQueryMap, e);
return ApiResult.fail("人脸验证失败,请重试");
}
}
private String getAuthFaceParamMap(FaceAuthParam faceAuthParam, String orderNo, String sign) {
Map<String, Object> paramMap = new HashMap<>(8);
paramMap.put("webankAppId", faceAuthProperties.getAppId());
paramMap.put("orderNo", orderNo);
paramMap.put("name", faceAuthParam.getName());
paramMap.put("idNo", faceAuthParam.getIdNo());
paramMap.put("userId", faceAuthParam.getUserId());
paramMap.put("sourcePhotoType", "1");
paramMap.put(VERSION, VERSION_VALUE);
paramMap.put("sign", sign);
paramMap.put("nonce", orderNo);
return JSON.toJSONString(paramMap);
}
/**
* 生成签名
*/
private String getSign(List<String> list,String signTicket) {
if (list == null) {
throw new NullPointerException("values is null");
}
list.removeAll(Collections.singleton(null));// remove null
list.add(signTicket);
java.util.Collections.sort(list);
StringBuilder sb = new StringBuilder();
for (String s : list) {
sb.append(s);
}
return Hashing.sha1().hashString(sb, Charsets.UTF_8).toString().toUpperCase();
}
private void publishFaceGetAccessTokenError(Map<String, Object> map, Exception exception) {
RepositoryExceptionEvent repositoryExceptionEvent = new RepositoryExceptionEvent(
FaceAuthEnum.TENCENT_FACE_ACCESS_TOKEN, JSONObject.toJSONString(map), exception);
EventPublisher.publishEvent(repositoryExceptionEvent);
}
private void publishFaceGetApiTicketError(Map<String, Object> map, Exception exception) {
RepositoryExceptionEvent repositoryExceptionEvent = new RepositoryExceptionEvent(
FaceAuthEnum.TENCENT_FACE_API_TICKET, JSONObject.toJSONString(map), exception);
EventPublisher.publishEvent(repositoryExceptionEvent);
}
private void publishFaceAuthError(String params, Exception exception) {
String json = StrUtil.format(PUBLISH_FACE_AUTH_FORM, HEADER_MAP, params);
RepositoryExceptionEvent repositoryExceptionEvent = new RepositoryExceptionEvent(
FaceAuthEnum.TENCENT_FACE_AUTH, json, exception);
EventPublisher.publishEvent(repositoryExceptionEvent);
}
}
注意事项
在进行人脸识别的过程中会有两次请求用到生成签名,一次是调用人脸识别合作方后台上传身份信息接口,另外就是调用sdk的时候,这两次签名生成所需要的的Ticket是不同的
第一次用的是下面
第二次用的是这个
不然会一直报签名错误