ali idcard verify

This commit is contained in:
ran.shang
2025-06-17 18:39:28 +08:00
parent f4a4fb9c76
commit 94a5f85c65
14 changed files with 413 additions and 26 deletions

View File

@@ -8,7 +8,9 @@ public enum FactorVerificationSourceTypeEnum {
FXQ("放心签", 1), FXQ("放心签", 1),
CL("创蓝", 2), CL("创蓝", 2),
SYS("系统", 3); SYS("系统", 3),
ALI("阿里", 4),
;
private final String desc; private final String desc;

View File

@@ -40,8 +40,6 @@ import lombok.extern.slf4j.Slf4j;
@SuppressWarnings("rawtypes,unchecked") @SuppressWarnings("rawtypes,unchecked")
public abstract class AbstractVerify<T extends FactorVerificationDTO> implements IVerify<T>, ITopicMqHandler<T>{ public abstract class AbstractVerify<T extends FactorVerificationDTO> implements IVerify<T>, ITopicMqHandler<T>{
private static final Integer DEFAULT_TYPE = FactorVerificationSourceTypeEnum.CL.getType();
static final Map<Integer, FactorVerificationSourceService> SOURCE_SERVICE_MAP = Maps.newConcurrentMap(); static final Map<Integer, FactorVerificationSourceService> SOURCE_SERVICE_MAP = Maps.newConcurrentMap();
/** /**
@@ -97,14 +95,9 @@ public abstract class AbstractVerify<T extends FactorVerificationDTO> implements
protected T syncBeforeVerify(T t) { protected T syncBeforeVerify(T t) {
// 认证源根据配置文件不同调用不同SDK 1放心签、2创蓝 // 认证源根据配置文件不同调用不同SDK 1放心签、2创蓝
String source = EnvironmentUtils.getProperty("alita.authenticationSource"); String source = EnvironmentUtils.getProperty("alita.authenticationSource");
int authenticationSource = DEFAULT_TYPE; int authenticationSource = FactorVerificationSourceTypeEnum.CL.getType();
try { try {
authenticationSource = Integer.parseInt(source); authenticationSource = Integer.parseInt(source);
//如果不是这两种认证源,用默认的源
if (!(FactorVerificationSourceTypeEnum.CL.getType().equals(authenticationSource)
|| FactorVerificationSourceTypeEnum.FXQ.getType().equals(authenticationSource))) {
authenticationSource = DEFAULT_TYPE;
}
} catch (NumberFormatException e) { } catch (NumberFormatException e) {
//doNothing //doNothing
} }

View File

@@ -0,0 +1,67 @@
package com.newyetai.alitaforward.verification.source.ali;
import cn.hutool.json.JSONUtil;
import com.newyetai.alitaforward.verification.constants.FactorVerificationSourceTypeEnum;
import com.newyetai.alitaforward.verification.dto.FactorVerificationDTO;
import com.newyetai.alitaforward.verification.dto.RealNameTwoFactorVerificationDTO;
import com.newyetai.alitaforward.verification.source.FactorVerificationSourceService;
import com.newyetai.alitaforward.verification.source.ali.mapstruct.AliVerifyMapMapper;
import com.newyetai.common.AlitaResult;
import com.newyetai.common.constant.AuthStatusEnum;
import com.newyetai.common.util.JsonUtils;
import com.newyetai.sdk.ali.dto.IdCardReq;
import com.newyetai.sdk.ali.dto.IdCardRes;
import com.newyetai.sdk.ali.service.AliVerifyService;
import com.newyetai.sdk.common.constant.SdkConstants;
import java.util.Objects;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service
@SuppressWarnings("unchecked")
public class ALiVerifySourceServiceImpl implements FactorVerificationSourceService {
@Resource(name = AliVerifyService.BEAN_ID)
private AliVerifyService aliVerifyService;
@Override
public RealNameTwoFactorVerificationDTO twoVerify(RealNameTwoFactorVerificationDTO verificationDTO) {
IdCardReq requestDTO = AliVerifyMapMapper.INSTANCE.toDTO(verificationDTO);
log.info("二要素认证:{}", JSONUtil.toJsonStr(requestDTO));
AlitaResult<IdCardRes> result = aliVerifyService.verify(requestDTO);
handlerResult(result, verificationDTO);
return verificationDTO;
}
private void handlerResult(AlitaResult<?> result, FactorVerificationDTO verificationDTO) {
verificationDTO.setInvokeData(JsonUtils.toJsonString(result));
AuthStatusEnum targetStatus = null;
if (SdkConstants.SDK_INVOKE_NOT_REACH_CODE.equals(result.getCode())) {
// 接口调起失败,未拿到返回结果,视为未调起
verificationDTO.setFailReason("调用异常,未调起第三方");
} else {
if (Boolean.TRUE.equals(result.getSuccess())) {
targetStatus = AuthStatusEnum.AUTH_SUCCESS;
} else {
targetStatus = AuthStatusEnum.AUTH_FAIL;
verificationDTO.setFailReason(result.getMsg());
}
}
if (Objects.nonNull(targetStatus)) {
verificationDTO.setStatus(targetStatus.getType());
}
}
@Override
public FactorVerificationSourceTypeEnum getSourceType() {
return FactorVerificationSourceTypeEnum.ALI;
}
}

View File

@@ -0,0 +1,24 @@
package com.newyetai.alitaforward.verification.source.ali.mapstruct;
import com.newyetai.alitaforward.verification.dto.RealNameTwoFactorVerificationDTO;
import com.newyetai.sdk.ali.dto.IdCardReq;
import com.newyetai.sdk.chuanglan.dto.RealNameTwoBaseRequestDTO;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
import org.mapstruct.factory.Mappers;
@Mapper
public interface AliVerifyMapMapper {
AliVerifyMapMapper INSTANCE = Mappers.getMapper(AliVerifyMapMapper.class);
@Mappings(value = {
@Mapping(target = "name", source = "dto.realName"),
@Mapping(target = "idcard", source = "dto.cardNo")
})
IdCardReq toDTO(RealNameTwoFactorVerificationDTO dto);
}

View File

@@ -57,6 +57,17 @@ public class StrUtils {
* @author sr on 2022-02-10 * @author sr on 2022-02-10
*/ */
public static String buildAscQueryValue(Object paramData) { public static String buildAscQueryValue(Object paramData) {
return buildAscQueryValue(paramData, true, null);
}
/**
* @param paramData 参数
* @param normal 是否正常(p1=v1&p2=v2)
* @param split 特殊分隔符(v1分隔符v2)
* @return
* @author sr on 2024-11-18
*/
public static String buildAscQueryValue(Object paramData, boolean normal, String split) {
Map<String, Object> paramDataMap = null; Map<String, Object> paramDataMap = null;
if (paramData instanceof Map) { if (paramData instanceof Map) {
paramDataMap = paramDataMap; paramDataMap = paramDataMap;
@@ -82,8 +93,48 @@ public class StrUtils {
} }
StringBuilder paramstr = new StringBuilder(); StringBuilder paramstr = new StringBuilder();
for (Entry<String, Object> entry : parameters.entrySet()) { for (Entry<String, Object> entry : parameters.entrySet()) {
if (normal) {
paramstr.append(entry.getKey()).append(CommonConstants.EQUAL) paramstr.append(entry.getKey()).append(CommonConstants.EQUAL)
.append(entry.getValue()).append(CommonConstants.AND); .append(entry.getValue()).append(CommonConstants.AND);
} else {
paramstr.append(entry.getValue()).append(split);
}
}
return paramstr.substring(0, paramstr.length() - 1);
}
/**
* 构建参数字符串(xx=**&xx=**)
* @param paramData
* @return
* @author sr on 2024-11-18
*/
public static String buildQueryValue(Object paramData) {
Map<String, Object> paramDataMap = null;
if (paramData instanceof Map) {
paramDataMap = paramDataMap;
} else {
try {
paramDataMap = JsonUtils.objToClassObj(paramData, Map.class);
} catch (Exception e) {
throw new BusinessException("参数对象格式错误");
}
}
if (paramDataMap == null || paramDataMap.isEmpty()) {
return null;
}
StringBuilder paramstr = new StringBuilder();
for (Entry<String, Object> entry : paramDataMap.entrySet()) {
Object value = entry.getValue();
if (value != null) {
paramstr.append(entry.getKey()).append(CommonConstants.EQUAL)
.append(entry.getValue()).append(CommonConstants.AND);
}
}
if (paramstr.length() == 0) {
return null;
} }
return paramstr.substring(0, paramstr.length() - 1); return paramstr.substring(0, paramstr.length() - 1);
} }

View File

@@ -0,0 +1,45 @@
package com.newyetai.sdk.ali.config;
import com.newyetai.sdk.chuanglan.config.ChuangLanCommonProperties;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Builder.Default;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@ConfigurationProperties(prefix = AliProperties.PREFIX)
@Data
@Component
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class AliProperties {
/** 配置前缀 */
public static final String PREFIX = "ali";
public static final String IDCARD_PREFIX = PREFIX + ".idcard";
/** 二要素配置 */
private IdcardProperties idcard;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public static class IdcardProperties {
/** 是否启用 **/
@Default
private Boolean enable = Boolean.FALSE;
/** 次数限制 **/
private Long numLimit;
private String url;
/** */
private String appcode;
}
}

View File

@@ -0,0 +1,27 @@
package com.newyetai.sdk.ali.dto;
import com.newyetai.sdk.common.dto.ISdkRequest;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.core.ParameterizedTypeReference;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class IdCardReq implements ISdkRequest<VerifyRes<IdCardRes>> {
private static ParameterizedTypeReference<VerifyRes<IdCardRes>> type = new ParameterizedTypeReference<VerifyRes<IdCardRes>>() {
};
private String name;
private String idcard;
@Override
public ParameterizedTypeReference<VerifyRes<IdCardRes>> getResponseType() {
return type;
}
}

View File

@@ -0,0 +1,27 @@
package com.newyetai.sdk.ali.dto;
import java.io.Serializable;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class IdCardRes implements Serializable {
/** code为200 data才会有值,400参数格式错误 */
public static final Integer SUC_CODE = 200;
/** 1.不一致 0.一致 */
public static final Integer SUC_RESULT = 0;
private String birthday;
private Integer result;
private String address;
private String orderNo;
private String sex;
private String desc;
}

View File

@@ -0,0 +1,17 @@
package com.newyetai.sdk.ali.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class VerifyRes<T> {
private String msg;
private String success;
private Integer code;
private T data;
}

View File

@@ -0,0 +1,14 @@
package com.newyetai.sdk.ali.service;
import com.newyetai.common.AlitaResult;
import com.newyetai.sdk.ali.dto.IdCardReq;
import com.newyetai.sdk.ali.dto.IdCardRes;
public interface AliVerifyService {
String BEAN_ID = "sdk.aliVerifyService";
String MOCK_BEAN_ID = "mock.aliVerifyService";
AlitaResult<IdCardRes> verify(IdCardReq req);
}

View File

@@ -0,0 +1,78 @@
package com.newyetai.sdk.ali.service.impl;
import com.newyetai.common.AlitaResult;
import com.newyetai.common.annotation.CheckAndMock;
import com.newyetai.common.util.JsonUtils;
import com.newyetai.common.util.StrUtils;
import com.newyetai.sdk.ali.config.AliProperties;
import com.newyetai.sdk.ali.config.AliProperties.IdcardProperties;
import com.newyetai.sdk.ali.dto.IdCardReq;
import com.newyetai.sdk.ali.dto.IdCardRes;
import com.newyetai.sdk.ali.dto.VerifyRes;
import com.newyetai.sdk.ali.service.AliVerifyService;
import com.newyetai.sdk.common.constant.SdkConstants;
import com.newyetai.sdk.common.dto.DefaultSdkInvokeLogDTO;
import com.newyetai.sdk.common.util.HttpUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
@Slf4j
@Service(AliVerifyService.BEAN_ID)
public class AliVerifyServiceImpl implements AliVerifyService {
private static RestTemplate restTemplate = HttpUtils.restTemplate;
@Autowired
private AliProperties aliProperties;
@Override
@CheckAndMock(mockClass = MockAliVerifyServiceImpl.class,
propertyPrefix = AliProperties.IDCARD_PREFIX)
public AlitaResult<IdCardRes> verify(IdCardReq req){
return this.verify(req, aliProperties.getIdcard());
}
public static AlitaResult<IdCardRes> verify(IdCardReq req, IdcardProperties idcardProperties){
VerifyRes<IdCardRes> res = null;
try {
try {
// 构建请求头
HttpHeaders header = new HttpHeaders();
header.add("Authorization", "APPCODE " + idcardProperties.getAppcode());
header.add("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
// 发送请求
HttpEntity<?> requestEntity = new HttpEntity(StrUtils.buildQueryValue(req), header);
ResponseEntity<VerifyRes<IdCardRes>> result = restTemplate.exchange(idcardProperties.getUrl(),
HttpMethod.POST, requestEntity, req.getResponseType());
res = result.getBody();
} catch (Exception e) {
log.info("invoke error :{}", e);
return AlitaResult.error(SdkConstants.SDK_HTTP_INVOKE_ERROR_CODE, e.getMessage());
}
try {
if (IdCardRes.SUC_CODE.equals(res.getCode()) && IdCardRes.SUC_RESULT.equals(res.getData().getResult())) {
return AlitaResult.success(res.getData());
}
return AlitaResult.error(SdkConstants.SDK_HTTP_INVOKE_RESPONSE_FAIL_CODE,
res.getCode() + res.getData().getDesc());
} catch (Exception e) {
return AlitaResult.error(SdkConstants.SDK_RESPONSE_CONVERT_ERROR_CODE,
e.getMessage());
}
} finally {
log.info("invoke:{}",
JsonUtils
.toJsonString(
DefaultSdkInvokeLogDTO.builder().requestData(req).responseData(res)
.build()));
}
}
}

View File

@@ -0,0 +1,19 @@
package com.newyetai.sdk.ali.service.impl;
import com.newyetai.common.AlitaResult;
import com.newyetai.sdk.ali.dto.IdCardReq;
import com.newyetai.sdk.ali.dto.IdCardRes;
import com.newyetai.sdk.ali.service.AliVerifyService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
@Slf4j
@Service(AliVerifyService.MOCK_BEAN_ID)
public class MockAliVerifyServiceImpl implements AliVerifyService {
@Override
public AlitaResult<IdCardRes> verify(IdCardReq req) {
log.info("ali idcard mock...");
return AlitaResult.success(IdCardRes.builder().result(IdCardRes.SUC_RESULT).build());
}
}

View File

@@ -52,7 +52,7 @@ file.storage.ali.bucketName=newyetai
#发号器 #发号器
#机器id:根据ip自己定义 #机器id:根据ip自己定义
code.snowflake.workid.192.168.31.234=23 code.snowflake.workid.192.168.31.135=23
code.snowflake.workid.121.37.2.171=1 code.snowflake.workid.121.37.2.171=1
code.snowflake.workid.139.159.237.199=2 code.snowflake.workid.139.159.237.199=2
code.snowflake.workid.192.168.3.2=4 code.snowflake.workid.192.168.3.2=4
@@ -144,16 +144,13 @@ sms.numLimit=300000
#短信验证码模板配置 #短信验证码模板配置
sms.phoneSms=SMS_478425358 sms.phoneSms=SMS_478425358
## 创蓝账号配置 #默认认证源:1fxq,2cl,4ali
chuanglan.enable=true alita.authenticationSource=4
chuanglan.phone=13816929046 #阿里二要素认证
chuanglan.domain=https://api.253.com ali.idcard.enable=true
chuanglan.appId=BkDWu80l ali.idcard.url=https://kzidcardv1.market.alicloudapi.com/api-mall/api/id_card/check
chuanglan.appSecret=Lvy1s1hu ali.idcard.appcode=728e8c05167a482093418707ca22822b
## 创蓝实名认证(基础二要素)开关、次数配置
chuanglan.realName2Base.enable=false
chuanglan.realName2Base.url=/open/idcard/id-card-auth
chuanglan.realName2Base.numLimit=1
#讯飞配置 #讯飞配置
xf.httpAPIPassword=EiORVeNtBjFOcUSKXanT:oIVlTRNhWcEDpksviZaG xf.httpAPIPassword=EiORVeNtBjFOcUSKXanT:oIVlTRNhWcEDpksviZaG

View File

@@ -0,0 +1,26 @@
package com.newyetai;
import com.newyetai.common.AlitaResult;
import com.newyetai.common.util.JsonUtils;
import com.newyetai.sdk.ali.config.AliProperties.IdcardProperties;
import com.newyetai.sdk.ali.dto.IdCardReq;
import com.newyetai.sdk.ali.dto.IdCardRes;
import com.newyetai.sdk.ali.service.impl.AliVerifyServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
@Slf4j
public class AliVerifyTest {
public static IdcardProperties idcardProperties = IdcardProperties.builder()
.url("https://kzidcardv1.market.alicloudapi.com/api-mall/api/id_card/check")
.appcode("728e8c05167a482093418707ca22822b").build();
@Test
public void idcard() {
IdCardReq req = IdCardReq.builder().name("吴国东").idcard("210221197907106318").build();
AlitaResult<IdCardRes> result = AliVerifyServiceImpl.verify(req, idcardProperties);
log.info("{}", JsonUtils.toJsonString(result));
}
}