package com.nova.sankuai.infra.utils.chuxin; import com.alibaba.fastjson.JSON; import com.nova.sankuai.domain.dto.chuxin.ChuxinData; import com.nova.sankuai.domain.dto.chuxin.ChuxinResult; import com.nova.sankuai.infra.config.CommonException; import com.nova.sankuai.infra.utils.ResultJson; import com.nova.sankuai.security.HttpClientUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; import java.io.UnsupportedEncodingException; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.*; /** * 储信数据·身份认证 */ @Component @RequiredArgsConstructor @Slf4j public class ChuxinDataUtil { /** * 登录管理平台应用管理可查看获取appId和appSecret */ private final static String appId = "1754b210"; private final static String tokenId = "82808081914b210201914b2102930000"; public ResultJson getRemoteResult(String idcard, String name) { // 接口地址,具体接口参见接口文档,每个接口有不同的url地址 String url = "https://kyc.chuxindata.com/identity/verifyIdcard"; Map param = new HashMap(); // 所需入参,请参照具体接口文档调整入参, 请注意区分大小写 param.put("name", name); param.put("idcard", idcard); // 生成TokenKey // 注意:进行MD5摘要时,不能传入appId参数 String tokenKey = getTokenKey(url, tokenId, param); param.put("tokenKey", tokenKey); // 注意:appId参数需要在请求的时候作为入参传入,appId不参与MD5摘要 param.put("appId", appId); // http的post请求 String result = HttpClientUtil.doPostChuxin(url, param); if (StringUtils.isBlank(result)) { log.error("储信数据·身份证二要素认证发生错误,icCard:{} name:{},发生错误,返回参数为:{}", idcard, name, result); throw new CommonException("服务器发生异常!"); } ChuxinData chuxinData = JSON.parseObject(result, ChuxinData.class); if (Objects.isNull(chuxinData)) { log.error("储信数据·身份证二要素认证发生错误,icCard:{} name:{},发生错误,返回参数为:{}", idcard, name, result); throw new CommonException("服务器发生异常!"); } if (chuxinData.getStatus().intValue() != 0) { log.info("储信数据·身份证二要素认证失败,icCard:{} name:{},返回参数为:{}", idcard, name, result); throw new CommonException("身份证和姓名不匹配!"); } ChuxinResult cr = chuxinData.getData(); if (Objects.isNull(cr)) { log.error("储信数据·身份证二要素认证发生错误,icCard:{} name:{},返回参数为:{}", idcard, name, result); throw new CommonException("服务器发生异常!"); } if (!"1".equals(cr.getResult())) { log.info("储信数据·身份证二要素认证失败,icCard:{} name:{},返回参数为:{}", idcard, name, result); throw new CommonException("身份证和姓名不匹配!"); } log.info("储信数据·身份证二要素认证成功,icCard:{} name:{},返回参数为:{}", idcard, name, result); return ResultJson.ok("ok"); } /** * 生成TokenKey * * @param url * @param tokenId * @param param * @return */ public String getTokenKey(String url, String tokenId, Map param) { String paramStr = sortParam(param); return md5Hex(url + tokenId + paramStr); } /** * 生成参数字符串,参数key按字典序排列 * * @param param * @return */ public String sortParam(Map param) { if (null == param || 0 == param.size()) { return ""; } // 排序键,按照字母先后进行排序 Iterator iterator = param.keySet().iterator(); String[] arr = new String[param.size()]; for (int i = 0; iterator.hasNext(); i++) { arr[i] = iterator.next(); } Arrays.sort(arr); // 生成进行MD5摘要的字符串 StringBuffer sb = new StringBuffer(); for (String key : arr) { String value = param.get(key); if (StringUtils.isNotBlank(value)) { sb.append(key).append("=").append(value).append(","); } } // 检查结果 if (sb.length() > 0) { return sb.substring(0, sb.length() - 1); } else { return ""; } } /** * 对字符串进行md5摘要,然后转化成16进制字符串 * 使用标准的md5摘要算法 * * @param text * @return */ public String md5Hex(String text) { try { MessageDigest md5 = MessageDigest.getInstance("MD5"); byte[] bytes = md5.digest(text.trim().getBytes("UTF-8")); StringBuilder sb = new StringBuilder(); for (int i = 0; i < bytes.length; i++) { int high = (bytes[i] >> 4) & 0x0f; int low = bytes[i] & 0x0f; sb.append(high > 9 ? (char) ((high - 10) + 'a') : (char) (high + '0')); sb.append(low > 9 ? (char) ((low - 10) + 'a') : (char) (low + '0')); } return sb.toString(); } catch (NoSuchAlgorithmException e) { log.error("储信数据·身份班证二要素认证:{},系统不支持MD5算法:", text, e); e.printStackTrace(); } catch (UnsupportedEncodingException e) { log.error("储信数据·身份班证二要素认证:{},系统不支持指定的编码格式:", text, e); } return null; } }