|
@@ -0,0 +1,253 @@
|
|
|
+package com.ematou.wxbase.service.impl;
|
|
|
+
|
|
|
+import cn.hutool.core.util.StrUtil;
|
|
|
+import com.ematou.wxbase.common.constant.RedisKey;
|
|
|
+import com.ematou.wxbase.common.constant.TokenType;
|
|
|
+import com.ematou.wxbase.common.web.R;
|
|
|
+import com.ematou.wxbase.entity.*;
|
|
|
+import com.ematou.wxbase.entity.dto.EidTokenRequestDTO;
|
|
|
+import com.ematou.wxbase.entity.vo.EidTokenResponseVO;
|
|
|
+import com.ematou.wxbase.exception.Assert;
|
|
|
+import com.ematou.wxbase.exception.ServiceException;
|
|
|
+import com.ematou.wxbase.mapper.EidMerchMapper;
|
|
|
+import com.ematou.wxbase.mapper.EidTokenRecordMapper;
|
|
|
+import com.ematou.wxbase.mapper.MerchAppMapper;
|
|
|
+import com.ematou.wxbase.mapper.MerchInfoMapper;
|
|
|
+import com.ematou.wxbase.service.EidService;
|
|
|
+import com.ematou.wxbase.service.OperationRecordService;
|
|
|
+import com.tencentcloudapi.common.Credential;
|
|
|
+import com.tencentcloudapi.common.exception.TencentCloudSDKException;
|
|
|
+import com.tencentcloudapi.common.profile.ClientProfile;
|
|
|
+import com.tencentcloudapi.common.profile.HttpProfile;
|
|
|
+import com.tencentcloudapi.faceid.v20180301.FaceidClient;
|
|
|
+import com.tencentcloudapi.faceid.v20180301.models.GetEidTokenConfig;
|
|
|
+import com.tencentcloudapi.faceid.v20180301.models.GetEidTokenRequest;
|
|
|
+import com.tencentcloudapi.faceid.v20180301.models.GetEidTokenResponse;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.data.redis.core.RedisTemplate;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import javax.annotation.Resource;
|
|
|
+import java.time.Duration;
|
|
|
+import java.time.LocalDateTime;
|
|
|
+import java.util.List;
|
|
|
+
|
|
|
+/**
|
|
|
+ * E证通业务实现类
|
|
|
+ *
|
|
|
+ * @author frankeleyn
|
|
|
+ * @email lvjian@qhdswl.com
|
|
|
+ * @date 2023/2/18 16:56
|
|
|
+ */
|
|
|
+@Service
|
|
|
+@Slf4j
|
|
|
+public class EidServiceImpl implements EidService {
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private MerchInfoMapper merchInfoMapper;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private MerchAppMapper merchAppMapper;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private EidMerchMapper eidMerchMapper;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private OperationRecordService recordService;
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private EidTokenRecordMapper eidTokenRecordMapper;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private RedisTemplate<String, Object> redisTemplate;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取E证通 Token
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public R<EidTokenResponseVO> getEidToken(EidTokenRequestDTO requestDTO) {
|
|
|
+ // 校验参数
|
|
|
+ validateParam(requestDTO);
|
|
|
+ // 校验商户
|
|
|
+ validateMerch(requestDTO.getMerchSn());
|
|
|
+ // 校验商户应用
|
|
|
+ validateMerchApp(requestDTO.getMerchSn(), requestDTO.getAppCode());
|
|
|
+ // 查询E证通商户配置
|
|
|
+ EidMerch eidMerch = eidMerchMapper.selectByMerchSn(requestDTO.getMerchSn());
|
|
|
+ Assert.notNull(eidMerch, "商户E证通配置不存在!");
|
|
|
+
|
|
|
+ // 响应数据
|
|
|
+ EidTokenResponseVO responseVO =
|
|
|
+ EidTokenResponseVO.builder()
|
|
|
+ .idCard(requestDTO.getIdCard())
|
|
|
+ .userName(requestDTO.getUserName())
|
|
|
+ .build();
|
|
|
+
|
|
|
+ // 获取E证通缓存键(功能名称:商户号:应用编码:核验人身份证号),例如: get_eid_token:merch123:kmall-pt:431422196503217896
|
|
|
+ String cacheKey =
|
|
|
+ RedisKey.GET_EID_TOKEN +
|
|
|
+ requestDTO.getMerchSn() + ":" +
|
|
|
+ requestDTO.getAppCode() + ":" +
|
|
|
+ requestDTO.getIdCard();
|
|
|
+ // 获取缓存中的 token
|
|
|
+ String cacheEidToken = (String) redisTemplate.opsForValue().get(cacheKey);
|
|
|
+ if (StrUtil.isNotBlank(cacheEidToken)) {
|
|
|
+ // 如果不为空,缓存存在
|
|
|
+ // 将 token 组装到响应数据中
|
|
|
+ throw new ServiceException("请勿重复请求!");
|
|
|
+ }else {
|
|
|
+ // 如果为空,缓存不存在
|
|
|
+ // 请求E证通 token
|
|
|
+ String eidToken = reqEidToken(eidMerch, requestDTO.getUserName(), requestDTO.getIdCard());
|
|
|
+ //String eidToken = "1a2b3c4d5e6f";
|
|
|
+ // 将E证通 token 设置进 Redis,并设置过期时间
|
|
|
+ redisTemplate.opsForValue().set(cacheKey, eidToken, Duration.ofSeconds(1L));
|
|
|
+ // 插入操作记录
|
|
|
+ insertOptRecord(requestDTO);
|
|
|
+ // 插入E证通操作记录
|
|
|
+ insertEidTokenRecord(requestDTO, eidToken);
|
|
|
+ // 返回结果组装
|
|
|
+ responseVO.setEidToken(eidToken);
|
|
|
+ }
|
|
|
+
|
|
|
+ // 返回结果
|
|
|
+ return R.success(responseVO);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取E证通结果
|
|
|
+ */
|
|
|
+ @Override
|
|
|
+ public R<?> getEidResult() {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 校验参数
|
|
|
+ *
|
|
|
+ * @param requestDTO
|
|
|
+ */
|
|
|
+ private void validateParam(EidTokenRequestDTO requestDTO) {
|
|
|
+ Assert.notEmpty(requestDTO.getMerchSn(), "商户号不能为空!");
|
|
|
+ Assert.notEmpty(requestDTO.getAppCode(), "应用编码不能为空!");
|
|
|
+ Assert.notEmpty(requestDTO.getUserName(), "用户名不能为空!");
|
|
|
+ Assert.notEmpty(requestDTO.getIdCard(), "用户身份证不能为空!");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 校验商户应用
|
|
|
+ *
|
|
|
+ * @param merchSn
|
|
|
+ * @param appCode
|
|
|
+ */
|
|
|
+ private void validateMerchApp(String merchSn, String appCode) {
|
|
|
+ MerchApp query = new MerchApp();
|
|
|
+ query.setMerchSn(merchSn);
|
|
|
+ query.setAppCode(appCode);
|
|
|
+ List<MerchApp> merchApps = merchAppMapper.selectByCondition(query);
|
|
|
+ Assert.notTrue(merchApps.size() < 1, "商户应用不存在!");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 校验商户
|
|
|
+ *
|
|
|
+ * @param merchSn
|
|
|
+ */
|
|
|
+ private void validateMerch(String merchSn) {
|
|
|
+ MerchInfo query = new MerchInfo();
|
|
|
+ query.setMerchSn(merchSn);
|
|
|
+ MerchInfo merchInfo = merchInfoMapper.selectOne(query);
|
|
|
+ Assert.notNull(merchInfo, "商户信息不存在!");
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 获取E证通 token
|
|
|
+ *
|
|
|
+ * @param eidMerch E证通商户配置
|
|
|
+ * @param userName 核验人姓名
|
|
|
+ * @param idCard 核验人身份证
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ private String reqEidToken(EidMerch eidMerch, String userName, String idCard) {
|
|
|
+ try {
|
|
|
+ // 创建访问凭据
|
|
|
+ Credential cred = new Credential(eidMerch.getSecretId(), eidMerch.getSecretKey());
|
|
|
+ // 实例化一个http选项,可选的,没有特殊需求可以跳过
|
|
|
+ HttpProfile httpProfile = new HttpProfile();
|
|
|
+ httpProfile.setEndpoint("faceid.tencentcloudapi.com");
|
|
|
+ // 实例化一个client选项,可选的,没有特殊需求可以跳过
|
|
|
+ ClientProfile clientProfile = new ClientProfile();
|
|
|
+ clientProfile.setHttpProfile(httpProfile);
|
|
|
+ // 实例化要请求产品的client对象,clientProfile是可选的
|
|
|
+ FaceidClient client = new FaceidClient(cred, "", clientProfile);
|
|
|
+ // 实例化一个请求对象,每个接口都会对应一个request对象
|
|
|
+ GetEidTokenRequest req = new GetEidTokenRequest();
|
|
|
+ // 设置商户 id
|
|
|
+ req.setMerchantId(eidMerch.getMerchId());
|
|
|
+ // 设置核验人姓名
|
|
|
+ req.setName(userName);
|
|
|
+ // 设置核验人身份证
|
|
|
+ req.setIdCard(idCard);
|
|
|
+ GetEidTokenConfig config = new GetEidTokenConfig();
|
|
|
+ config.setInputType("4");
|
|
|
+ req.setConfig(config);
|
|
|
+ // 返回的resp是一个GetEidTokenResponse的实例,与请求对象对应
|
|
|
+ GetEidTokenResponse resp = client.GetEidToken(req);
|
|
|
+ // 输出json格式的字符串回包
|
|
|
+ log.info("E证通返回结果: " + GetEidTokenResponse.toJsonString(resp));
|
|
|
+ // 获取 EidToken
|
|
|
+ String eidToken = resp.getEidToken();
|
|
|
+ // 返回 token
|
|
|
+ return eidToken;
|
|
|
+ } catch (TencentCloudSDKException e) {
|
|
|
+ log.error("腾讯云 SDK 请求E证通 token 异常.", e);
|
|
|
+ throw new ServiceException("请求E证通异常!");
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 插入操作记录
|
|
|
+ *
|
|
|
+ * @param requestDTO
|
|
|
+ */
|
|
|
+ private void insertOptRecord(EidTokenRequestDTO requestDTO) {
|
|
|
+ OperationRecord operationRecord =
|
|
|
+ OperationRecord.builder()
|
|
|
+ .appCode(requestDTO.getAppCode())
|
|
|
+ .merchSn(requestDTO.getMerchSn())
|
|
|
+ .tokenType(TokenType.EID_TOKEN.getItem())
|
|
|
+ .build();
|
|
|
+ // 插入操作记录
|
|
|
+ recordService.insertRecord(operationRecord);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 插入E证通 token 记录
|
|
|
+ *
|
|
|
+ * @param requestDTO
|
|
|
+ * @param eidToken
|
|
|
+ */
|
|
|
+ private void insertEidTokenRecord(EidTokenRequestDTO requestDTO, String eidToken) {
|
|
|
+ // token 生成时间
|
|
|
+ LocalDateTime generationTime = LocalDateTime.now();
|
|
|
+ // 过期时间, 生成时间 + 60s
|
|
|
+ LocalDateTime expireTime = generationTime.plusMinutes(8L);
|
|
|
+ EidTokenRecord eidTokenRecord = EidTokenRecord.builder()
|
|
|
+ .merchSn(requestDTO.getMerchSn())
|
|
|
+ .appCode(requestDTO.getAppCode())
|
|
|
+ .token(eidToken)
|
|
|
+ .generationTime(generationTime)
|
|
|
+ .expireTime(expireTime)
|
|
|
+ .idCard(requestDTO.getIdCard())
|
|
|
+ .userName(requestDTO.getUserName())
|
|
|
+ .build();
|
|
|
+ int insert = eidTokenRecordMapper.insert(eidTokenRecord);
|
|
|
+ Assert.notTrue(insert < 1, "插入E证通 token 记录失败!");
|
|
|
+ }
|
|
|
+
|
|
|
+}
|