Authored by mali

实名认知

... ... @@ -6,7 +6,7 @@
<parent>
<groupId>com.yoho</groupId>
<artifactId>parent</artifactId>
<version>1.7.6-SNAPSHOT</version>
<version>1.7.7-SNAPSHOT</version>
</parent>
<groupId>com.yohoufo.fore</groupId>
... ...
... ... @@ -149,7 +149,10 @@
<artifactId>alipay-sdk-java</artifactId>
<version>3.4.27.ALL</version>
</dependency>
<dependency>
<groupId>com.yoho.core</groupId>
<artifactId>security</artifactId>
</dependency>
<dependency>
<groupId>xom</groupId>
<artifactId>xom</artifactId>
... ...
... ... @@ -224,6 +224,14 @@ public class CacheService {
yhRedisTemplate.delete(getZhiMaCertRedisKeyBuilder(uid));
}
public void delZhiMaCertNoException(Integer uid){
try {
delZhiMaCert(uid); //(9)删除实名认证信息缓存
}catch(Exception e){
logger.warn("delZhiMaCertNoException: delZhiMaCert redis fail, uid is {}, e is {}", uid, e);
}
}
public Long getPhotoCheckCount(String dayStr,Integer uid){
RedisKeyBuilder cacheKey = getPhotoCheckRedisKeyBuilder(dayStr,uid);
Long count = get(cacheKey,Long.class);
... ...
... ... @@ -5,6 +5,7 @@ import com.yoho.tools.common.beans.ApiResponse;
import com.yohobuy.ufo.model.user.resp.AuthorizeResultRespVO;
import com.yohoufo.common.exception.GatewayException;
import com.yohoufo.common.exception.VersionNotSupportException;
import com.yohoufo.common.utils.AppVersion;
import com.yohoufo.dal.user.model.ZhiMaCert;
import com.yohoufo.user.common.IDCardUtils;
import com.yohoufo.user.requestVO.RealNameAuthorizeReqVO;
... ... @@ -52,9 +53,13 @@ public class CertificationController {
throw new GatewayException(400, "身份证号、姓名不能为空!");
}
//(2)开始执行实名认证流程。
AuthorizeResultRespVO respBO = certificationService.beginCertificate(reqVO);
AuthorizeResultRespVO respBO = null;
//(2)开始执行实名认证流程。 新版本使用支付宝的实名认证,并且包含了身份证封面的认证
if(StringUtils.isNotBlank(reqVO.getApp_version()) && AppVersion.of(reqVO.getApp_version()).greaterThanOrEquals(AppVersion.of("6.10.3"))){
respBO = certificationService.beginCertificateEx(reqVO);
} else {
respBO = certificationService.beginCertificate(reqVO);
}
//(3)组装返回
ApiResponse apiResponse=new ApiResponse();
apiResponse.setData(respBO);
... ... @@ -74,8 +79,14 @@ public class CertificationController {
if (reqVO == null || StringUtils.isBlank(reqVO.getZhiMaBizNo())){
throw new GatewayException(400, "参数错误,zhiMaBizNo不能为空!");
}
ApiResponse result;
//(2) 调用支付宝接口查询认证结果
ApiResponse result = certificationService.queryUserCertify(reqVO);
if(StringUtils.isNotBlank(reqVO.getApp_version()) && AppVersion.of(reqVO.getApp_version()).greaterThanOrEquals(AppVersion.of("6.10.3"))){
result = certificationService.queryUserCertifyEx(reqVO);
} else {
result = certificationService.queryUserCertify(reqVO);
}
logger.info("CertificationController.alipayCertifyResultQuery: End. result is {}", result);
return result;
}
... ...
... ... @@ -10,6 +10,8 @@ import com.alipay.api.request.AlipayUserCertifyOpenQueryRequest;
import com.alipay.api.response.AlipayUserCertifyOpenCertifyResponse;
import com.alipay.api.response.AlipayUserCertifyOpenInitializeResponse;
import com.alipay.api.response.AlipayUserCertifyOpenQueryResponse;
import com.yoho.core.security.AlipayOpenapi;
import com.yoho.core.security.AlipayOpenapiHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.UUID;
... ... @@ -35,6 +37,12 @@ public class AlipayCertHelper {
*/
private static String APP_ID = "2016091401906455";
/**
* 支付宝应用APPID
*/
private static String NEW_APP_ID = "2021001108677633";
/**
* 支付宝请求地址
*/
... ... @@ -115,6 +123,58 @@ public class AlipayCertHelper {
}
/**
* 支付宝刷脸实名认证初始化
*
* @return
*/
public static String alipayCertifyInitEx(String certName, String certNO,AlipayOpenapiHelper alipayOpenapiHelper) {
AlipayOpenapi alipayOpenapi = alipayOpenapiHelper.findAlipayOpenapi(NEW_APP_ID);
AlipayClient alipayClient = new DefaultAlipayClient(ALI_URL, NEW_APP_ID, alipayOpenapi.getPrivateKey(), FORMAT, CHARSET, alipayOpenapi.getAliPubicKey(), SIGN_TYPE);
AlipayUserCertifyOpenInitializeRequest request = new AlipayUserCertifyOpenInitializeRequest();
//构造身份信息json对象
JSONObject identityObj = new JSONObject();
//身份类型,必填,详细取值范围请参考接口文档说明
identityObj.put("identity_type", "CERT_INFO");
//证件类型,必填,详细取值范围请参考接口文档说明
identityObj.put("cert_type", "IDENTITY_CARD");
//真实姓名,必填
identityObj.put("cert_name", certName);
//证件号码,必填
identityObj.put("cert_no", certNO);
//构造商户配置json对象
JSONObject merchantConfigObj = new JSONObject();
// 设置回调地址,必填. 如果需要直接在支付宝APP里面打开回调地址使用alipay协议,参考下面的案例:appId用固定值 20000067,url替换为urlEncode后的业务回跳地址
merchantConfigObj.put("return_url", "yohobuyufo://www.yohobuy.com/ufo");
//构造身份认证初始化服务业务参数数据
JSONObject bizContentObj = new JSONObject();
//商户请求的唯一标识,推荐为uuid,必填
bizContentObj.put("outer_order_no", UUID.randomUUID());
bizContentObj.put("biz_code", "CERT_PHOTO");
bizContentObj.put("identity_param", identityObj);
bizContentObj.put("merchant_config", merchantConfigObj);
request.setBizContent(bizContentObj.toString());
//发起请求
try {
AlipayUserCertifyOpenInitializeResponse response = alipayClient.execute(request);
if (response.isSuccess()) {
String certifyId = response.getCertifyId();
logger.info("AlipayCertHelper.alipayCertifyInit: init result. certID is {}, certName is {}, certifyId is {}", certNO, certName, certifyId);
return certifyId;
}
}catch (Exception e){
logger.error("AlipayCertHelper.alipayCertifyInit: Alipay init failed. certID is {}, certName is {}", certNO, certName, e);
}
return null;
}
public static String alipayCertifyCertify(String certify_id) {
//获取alipay client
AlipayClient alipayClient = new DefaultAlipayClient(ALI_URL, APP_ID, APP_PRIVATE_KEY, FORMAT, CHARSET, ALIPAY_PUBLIC_KEY, SIGN_TYPE);
... ... @@ -152,21 +212,54 @@ public class AlipayCertHelper {
}
public static AlipayUserCertifyOpenQueryResponse alipayCertifyResultEx(String certify_id, AlipayOpenapiHelper alipayOpenapiHelper) throws AlipayApiException {
AlipayOpenapi alipayOpenapi = alipayOpenapiHelper.findAlipayOpenapi(NEW_APP_ID);
public static void main(String[] args) throws AlipayApiException {
String certifyId = AlipayCertHelper.alipayCertifyInit("邓新飞", "340604198806232218");
String certifyUrl = AlipayCertHelper.alipayCertifyCertify(certifyId);
AlipayCertHelper.alipayCertifyResult(certifyId);
System.out.println(certifyUrl);
}
//获取alipay client
AlipayClient alipayClient = new DefaultAlipayClient(ALI_URL, NEW_APP_ID, alipayOpenapi.getPrivateKey(), FORMAT, CHARSET, alipayOpenapi.getAliPubicKey(), SIGN_TYPE);
AlipayUserCertifyOpenQueryRequest request = new AlipayUserCertifyOpenQueryRequest ();
JSONObject bizContentObj = new JSONObject();
bizContentObj.put("certify_id", certify_id);//本次申请操作的唯一标识,由开放认证初始化接口调用后生成
request.setBizContent(bizContentObj.toString());
return alipayClient.execute(request);
}
public static void main(String[] args) throws AlipayApiException {
String certifyId = AlipayCertHelper.alipayCertifyInitEx("邓新飞", "340604198806232218", null);
String certifyUrl = AlipayCertHelper.alipayCertifyCertify(certifyId);
AlipayCertHelper.alipayCertifyResult(certifyId);
System.err.println(certifyUrl);
}
public static String alipayCertifyCertifyEx(String certifyId, AlipayOpenapiHelper alipayOpenapiHelper) {
AlipayOpenapi alipayOpenapi = alipayOpenapiHelper.findAlipayOpenapi(NEW_APP_ID);
//获取alipay client
AlipayClient alipayClient = new DefaultAlipayClient(ALI_URL, NEW_APP_ID, alipayOpenapi.getPrivateKey(), FORMAT, CHARSET, alipayOpenapi.getAliPubicKey(), SIGN_TYPE);
AlipayUserCertifyOpenCertifyRequest request = new AlipayUserCertifyOpenCertifyRequest();
//设置certifyId
JSONObject bizContentObj = new JSONObject();
bizContentObj.put("certify_id", certify_id);
request.setBizContent(bizContentObj.toString());
request.setReturnUrl("yohobuyufo://www.yohobuy.com/ufo?certify_id=" + certify_id + "&");
//生成请求链接,这里一定要使用GET模式
try {
AlipayUserCertifyOpenCertifyResponse response = alipayClient.pageExecute(request, "GET");
if (response.isSuccess()) {
String certifyUrl = response.getBody();
logger.info("AlipayCertHelper.alipayCertifyCertify: alipay certify result. certify_id is {}, certifyUrl is {}", certify_id, certifyUrl);
return certifyUrl;
}
}catch (Exception e){
logger.error("AlipayCertHelper.alipayCertifyCertify: alipay certify failed. certify_id is {}", certify_id);
}
return null;
}
}
... ...
... ... @@ -26,4 +26,17 @@ public interface IAlipayService {
*
*/
void beginAlipayCert(RealNameAuthorizeReqVO reqVO, ZhiMaCert zhiMaCert, AuthorizeResultRespVO respBO);
/**
* 开始支付宝刷脸实名认证
* 1、实名认证初始化,获取证书certificate_id
* 2、开始实名认证,获取认证URL 认证包含身份证图片的认证
*
* @param reqVO
* @param zhiMaCert
* @param respBO 响应参数
*
*/
void beginAlipayCertEx(RealNameAuthorizeReqVO reqVO, ZhiMaCert zhiMaCert, AuthorizeResultRespVO respBO);
}
... ...
... ... @@ -31,4 +31,20 @@ public interface ICertificationService {
*/
ApiResponse queryUserCertify(RealNameAuthorizeReqVO reqVO);
/**
* 开始实名认证(支付宝实名身份证认证)
*
* @param realNameAuthorizeReqVO 实名认证用户信息(包含身份证照片,姓名,身份证号码)
* @return 认证结果
*/
AuthorizeResultRespVO beginCertificateEx(RealNameAuthorizeReqVO realNameAuthorizeReqVO);
/**
* 身份认证记录查询
* @param reqVO
* @return
*/
ApiResponse queryUserCertifyEx(RealNameAuthorizeReqVO reqVO);
}
... ...
package com.yohoufo.user.service.impl;
import com.yoho.core.security.AlipayOpenapiHelper;
import com.yoho.error.exception.ServiceException;
import com.yohobuy.ufo.model.user.resp.AuthorizeResultRespVO;
import com.yohoufo.common.utils.StringUtil;
... ... @@ -31,6 +32,9 @@ public class AlipayServiceImpl implements IAlipayService {
@Autowired
private IZhiMaCertDao zhiMaCertDao;
@Autowired
AlipayOpenapiHelper alipayOpenapiHelper;
@Override
public void beginAlipayCert(RealNameAuthorizeReqVO reqVO, ZhiMaCert zhiMaCert, AuthorizeResultRespVO respBO){
logger.info("BeginAlipayCert: Begin alipay certification. reqVO is {}, zhiMaCert is {}", reqVO, zhiMaCert);
... ... @@ -69,4 +73,42 @@ public class AlipayServiceImpl implements IAlipayService {
respBO.setZhiMaUrl(certifyUrl);
}
@Override
public void beginAlipayCertEx(RealNameAuthorizeReqVO reqVO, ZhiMaCert zhiMaCert, AuthorizeResultRespVO respBO){
logger.info("BeginAlipayCert: Begin alipay certification. reqVO is {}, zhiMaCert is {}", reqVO, zhiMaCert);
// 闲鱼订单跳过百度刷脸
if(StringUtils.isNotEmpty(reqVO.getClient_type()) && "h5".equals(reqVO.getClient_type())){
logger.info("BeginAlipayCert: client type is h5, reqVO is {}, zhiMaCert is {}", reqVO, zhiMaCert);
zhiMaCertDao.updateIdleFishValidStatus(zhiMaCert.getId());
respBO.setCallZhiMa("1");
respBO.setZhiMaCertId(zhiMaCert.getId());
return;
}
//(1)支付宝刷脸认证初始化
String certifyId = AlipayCertHelper.alipayCertifyInitEx(reqVO.getCertName(), reqVO.getCertNo(), alipayOpenapiHelper);
logger.info("BeginAlipayCert: alipay init result. uid is {}, certNO is {}, certName is {}, certifyId is {}", reqVO.getUid(), reqVO.getCertNo(), reqVO.getCertName(), certifyId);
if(StringUtils.isEmpty(certifyId)){
logger.error("BeginAlipayCert: alipay init ERROR. uid is {}, certNO is {}, certName is {}, certifyId is {}", reqVO.getUid(), reqVO.getCertNo(), reqVO.getCertName(), certifyId);
throw new ServiceException(400, "支付宝实名认证出错");
}
//(2)开始刷脸认证,获取认证的URL(关键步骤)
String certifyUrl = AlipayCertHelper.alipayCertifyCertifyEx(certifyId, alipayOpenapiHelper);
logger.info("BeginAlipayCert: alipay certify result. uid is {}, certNO is {}, certName is {}, certifyId is {}, url is {}", reqVO.getUid(), reqVO.getCertNo(), reqVO.getCertName(), certifyId, certifyUrl);
if(StringUtils.isEmpty(certifyId)){
logger.info("BeginAlipayCert: alipay certify ERROR. uid is {}, certNO is {}, certName is {}, certifyId is {}, url is {}", reqVO.getUid(), reqVO.getCertNo(), reqVO.getCertName(), certifyId, certifyUrl);
throw new ServiceException(400, "支付宝实名认证出错");
}
//(3)更新数据库记录,将认证ID更新入库
zhiMaCertDao.updateBizNoByByPrimaryKey(zhiMaCert.getId(), certifyId);
//(4)组装返回信息
respBO.setCallZhiMa("1");
respBO.setZhiMaCertId(zhiMaCert.getId());
respBO.setZhiMaBizNo(certifyId);
respBO.setZhiMaUrl(certifyUrl);
}
}
... ...
... ... @@ -2,6 +2,7 @@ package com.yohoufo.user.service.impl;
import com.alibaba.fastjson.JSONObject;
import com.alipay.api.response.AlipayUserCertifyOpenQueryResponse;
import com.yoho.core.security.AlipayOpenapiHelper;
import com.yoho.tools.common.beans.ApiResponse;
import com.yohobuy.ufo.model.user.resp.AuthorizeResultRespVO;
import com.yohoufo.common.constant.CertPhotoEnum;
... ... @@ -51,6 +52,9 @@ public class CertificationServiceImpl implements ICertificationService {
@Value("${ufo.certification.timesLimit:3}")
private int certTimesLimit;
@Autowired
AlipayOpenapiHelper alipayOpenapiHelper;
@Override
public AuthorizeResultRespVO beginCertificate(RealNameAuthorizeReqVO reqVO) {
logger.info("BeginCertificate: Begin select valid certification record. reqVO is {}", reqVO);
... ... @@ -168,6 +172,124 @@ public class CertificationServiceImpl implements ICertificationService {
}
}
@Override
public ApiResponse queryUserCertifyEx(RealNameAuthorizeReqVO reqVO) {
try {
logger.info("queryUserCertify: enter. reqVO is {}", reqVO);
//(0) 删除实名认证信息缓存
try {
cacheService.delZhiMaCert(reqVO.getUid());
}catch(Exception e){
logger.warn("queryUserCertify: delZhiMaCert redis fail, uid is {}, e is {}");
}
//(1) 根据 bizNo 查询认证信息是否存在
ZhiMaCert zhiMaCert = zhiMaCertDao.selectByBizNo(reqVO.getZhiMaBizNo());
if (zhiMaCert == null || StringUtils.isEmpty(zhiMaCert.getBizNo())) {
logger.warn("queryUserCertify: certInfo is null. reqVO is {}", reqVO);
throw new UfoServiceException(400, "未找到身份认证信息!");
}
//(2) 身份认证结果获取(调用支付宝接口)并更新
AlipayUserCertifyOpenQueryResponse response = AlipayCertHelper.alipayCertifyResultEx(zhiMaCert.getBizNo(), alipayOpenapiHelper);
logger.info("queryUserCertify: queryUserCert by alipay success. reqVO is {}, certResult is {}", reqVO, response);
if(!response.isSuccess()){
logger.info("queryUserCertify: fail. reqVO is {}", reqVO);
throw new UfoServiceException(400, "查询身份认证结果失败");
}
JSONObject result = JSONObject.parseObject(response.getBody()).getJSONObject("alipay_user_certify_open_query_response");
if("Success".equals(result.get("msg")) && "T".equals(result.get("passed"))){
int updateCount = zhiMaCertDao.updateValidStatusByPrimaryKey(zhiMaCert.getId());
if(updateCount < 1){
logger.warn("queryUserCertify: update certResult fail. reqVO is {}", reqVO);
throw new UfoServiceException(400, "更新身份认证结果失败!");
}
logger.info("queryUserCertify: userCert pass. reqVO is {}, certResult is {}", reqVO, response);
return new ApiResponse<>(200, "身份认证通过", true);
}else{
String errorMsg = result.getString("sub_msg");//认证不通过可能是出现异常情况
logger.info("queryUserCertify: userCert notPass. reqVO is {}, certResult is {}", reqVO, response);
return new ApiResponse<>(400, StringUtils.isEmpty(errorMsg) ? "身份认证不通过" : errorMsg ,false);
}
}catch(Exception e){
logger.warn("queryUserCertify: error. reqVO is {}, e is {}", reqVO, e);
throw new UfoServiceException(400, "查询身份认证结果失败");
}
}
/**
* 开始实名认证(支付宝实名身份证认证)
* @param reqVO 实名认证用户信息(包含身份证照片,姓名,身份证号码)
* @return 认证结果
*/
public AuthorizeResultRespVO beginCertificateEx(RealNameAuthorizeReqVO reqVO) {
logger.info("beginCertificateEx: Begin select valid certification record. reqVO is {}", reqVO);
this.checkIsLimited(reqVO.getUid()); //(1)判断当前实名认证次数是否超限(每个用户一天最多实名认证3次)
int uid = reqVO.getUid(); //(2)直接查询当前UID实名认证的记录
ZhiMaCert zhiMaCert = zhiMaCertDao.selectLatestCertificateByUid(uid);
logger.info("beginCertificateEx: get user certification history by uid. uid is {}, zhiMaCert is {}", uid, zhiMaCert);
//(3)是否已经认证通过,认证通过的直接返回.(以防万一,一般都是没有认证通过的)
if(null != zhiMaCert && CertPhotoEnum.isValidStatus(zhiMaCert.getValidPhoto()) && 1 == zhiMaCert.getValidStatus()){
logger.info("beginCertificateEx: user has certification already. uid is {}", uid);
throw new UfoServiceException(400, "已实名认证!");
}
//(4)如果客户端传入的身份信息是隐位信息,那么将身份信息进行补全。
if(null != zhiMaCert && (reqVO.getCertName().contains("*") || reqVO.getCertNo().contains("*"))){
reqVO.setCertName(zhiMaCert.getCertName());
reqVO.setCertNo(zhiMaCert.getCertNo());
logger.info("beginCertificateEx:zhiMaCertWithPhotoCheckInit reset mask ,zhiMaCert {} ,new reqVO is {}", zhiMaCert ,reqVO);
}
//(5) 判断用户新传入的身份信息,是否与历史认证一致,如果不一致,需要重新进行OCR识别+支付宝刷脸认证。
if(null != zhiMaCert && (!reqVO.getCertName().equals(zhiMaCert.getCertName()) || !reqVO.getCertNo().equals(zhiMaCert.getCertNo()))){
logger.info("beginCertificateEx: request cert info not matched in db. reqVO is {}, zhiMaCert is {}", reqVO, zhiMaCert);
zhiMaCert = null;
}
//----------------------以下是需要实名认证(身份证OCR识别 + 支付宝刷脸认证)-------------------------------
AuthorizeResultRespVO respBO = new AuthorizeResultRespVO();
respBO.setCallZhiMa("0");
//(6)身份证OCR识别(已经识别过将不会继续识别)
if(null == zhiMaCert || !CertPhotoEnum.isValidStatus(zhiMaCert.getValidPhoto())){
ocrCertPhotoService.IDOCRIdentification(reqVO, zhiMaCert); //OCR身份证识别
logger.info("beginCertificateEx: ocr identification result. reqVO is {}", reqVO);
}
//(7)如果是首次认证,记录入库,否则更新认证记录
if(null == zhiMaCert){
zhiMaCert = new ZhiMaCert();
zhiMaCert.setUid(reqVO.getUid());
zhiMaCert.setValidStatus(9);//用户还未授权,暂时未生效 ,初始值为9
zhiMaCert.setCertName(reqVO.getCertName());
zhiMaCert.setCertNo(reqVO.getCertNo());
zhiMaCert.setImageUrl(reqVO.getFrontImageUrl()+","+reqVO.getBackImageUrl());
zhiMaCert.setValidPhoto(1); // 实名和身份证照片是一起验证的
zhiMaCert.setCreateTime(System.currentTimeMillis()/1000);
zhiMaCert.setUpdateTime(System.currentTimeMillis()/1000);
zhiMaCertDao.insertAndGetID(zhiMaCert);
}else if(null != zhiMaCert && !CertPhotoEnum.isValidStatus(zhiMaCert.getValidPhoto())){
zhiMaCertDao.updatePhotoResult(zhiMaCert.getId(), reqVO.getFrontImageUrl()+","+reqVO.getBackImageUrl(),
reqVO.getPhotoValidStatus(), System.currentTimeMillis()/1000);
}
logger.info("beginCertificateEx: save db success. reqVO is {}, zhiMaCert is {}", reqVO, zhiMaCert);
//(8)支付宝实名认证(如果已经认证过了,将不会继续认证)
if(null == zhiMaCert || 1 != zhiMaCert.getValidStatus()) {
alipayService.beginAlipayCertEx(reqVO, zhiMaCert, respBO); //开始支付宝刷脸认证
logger.info("beginCertificateEx: call alipay certify end. reqVO is {}, zhiMaCert is {}, respBO is {}", reqVO, zhiMaCert, respBO);
}
cacheService.delZhiMaCertNoException(reqVO.getUid()); //(9)删除实名认证信息缓存
return respBO;
}
/**
* 判断当前用户使用实名认证的次数是否超限,默认3次
* @param uid
... ...