From 5441c04743b956f3b619d8e3ca11b56610e25500 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A2=A8=E5=A4=A7=E5=8F=94?= <494979559@qq.com> Date: Fri, 20 Sep 2024 16:42:12 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=B4=E6=97=B6=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/ruoyi/common/constant/HttpStatus.java | 9 +++ .../common/valid/face/FaceResponseData.java | 49 ++++++++++++ .../ruoyi/common/valid/face/FaceUtils.java | 55 +++++++++++++ .../valid/liveness/LivenessResponseBody.java | 17 ++++ .../liveness/LivenessResponseQueryData.java | 21 +++++ .../liveness/LivenessResponseTokenData.java | 14 ++++ .../common/valid/liveness/LivenessUtils.java | 79 +++++++++++++++++++ .../impl/TransactionBillServiceImpl.java | 6 +- .../ss/user/domain/dto/UserRealNameDTO.java | 2 + .../ss/user/domain/vo/UserRealNameVO.java | 16 ++++ .../user/service/impl/SmUserServiceImpl.java | 20 +++-- .../web/controller/app/AppUserController.java | 2 +- .../src/main/resources/application.yml | 12 ++- 13 files changed, 291 insertions(+), 11 deletions(-) create mode 100644 smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/valid/face/FaceResponseData.java create mode 100644 smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/valid/face/FaceUtils.java create mode 100644 smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/valid/liveness/LivenessResponseBody.java create mode 100644 smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/valid/liveness/LivenessResponseQueryData.java create mode 100644 smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/valid/liveness/LivenessResponseTokenData.java create mode 100644 smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/valid/liveness/LivenessUtils.java create mode 100644 smart-switch-service/src/main/java/com/ruoyi/ss/user/domain/vo/UserRealNameVO.java diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/constant/HttpStatus.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/constant/HttpStatus.java index b377d4bd..6f573bd2 100644 --- a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/constant/HttpStatus.java +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/constant/HttpStatus.java @@ -92,4 +92,13 @@ public class HttpStatus */ public static final int WARN = 601; + /** + * 未实名 + */ + public static final int NO_REAL_NAME = 10001; + + /** + * 限制提现 + */ + public static final int LIMIT_WITHDRAW = 10002; } diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/valid/face/FaceResponseData.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/valid/face/FaceResponseData.java new file mode 100644 index 00000000..e0fe834e --- /dev/null +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/valid/face/FaceResponseData.java @@ -0,0 +1,49 @@ +package com.ruoyi.common.valid.face; + +import com.alibaba.fastjson2.annotation.JSONField; +import lombok.Data; + +import java.math.BigDecimal; + +/** + * @author wjh + * 2024/9/20 + */ +@Data +public class FaceResponseData { + + @JSONField(name = "order_no") + private String orderNo; + + //score 比较结果分值,0-1之间的小数,参考指标:0.40以下系统判断为不同人;0.40-0.45不能确定是否为同一人;0.45以上系统判断为同一人 + private BigDecimal score; + + private String msg; + + /** + * incorrect详解 + * 1、编号说明 + * 100 比对成功,还要根据score的值来判断是否同一人 + * 101 身份证号码姓名不一致 + * 102 库中无此号 + * 103 身份核验成功,数据非法,公安已经进行了身份核验(姓名身份证号码一致,公安返回的错误: 除库中无照片(109),特征提取失败(110),检测到多于一张人脸(111),人脸识别系统异常(106),图片不合法(112)以外的情况 + * 104 数据非法,公安未进行身份核验前图片校验,公安返回的错误: 除照片质量不合格(107),上传图片文件过大(108),人像比对服务异常(113)以外的情况 + * 106 身份核验成功,人脸识别系统异常 + * 107 照片质量不合格 + * 108 上传图片文件过大 + * 109 身份核验成功,库中无照片 + * 110 身份核验成功,特征提取失败 + * 111 身份核验成功,检测到多于一张人脸 + * 112 身份核验成功,图片不合法 + * 113 人像比对服务异常 + * 103 身份核验成功,数据非法 + * + * 2、103,104区别 + * 103证件号码一致,照片比对时报错;104未进行证件号校验,数据检验报错。 + * + * 3、104,107区别 + * 107检测到的公安错误;104未检测到的公安错误 + */ + private Integer incorrect; + +} diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/valid/face/FaceUtils.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/valid/face/FaceUtils.java new file mode 100644 index 00000000..2f66b905 --- /dev/null +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/valid/face/FaceUtils.java @@ -0,0 +1,55 @@ +package com.ruoyi.common.valid.face; + +import com.alibaba.fastjson2.JSON; +import com.ruoyi.common.utils.ServiceUtil; +import com.ruoyi.common.utils.http.AliHttpUtils; +import com.ruoyi.common.utils.spring.SpringUtils; +import com.ruoyi.common.valid.liveness.LivenessResponseBody; +import com.ruoyi.common.valid.liveness.LivenessResponseTokenData; +import org.apache.http.HttpResponse; +import org.apache.http.util.EntityUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author wjh + * 2024/9/20 + */ +public class FaceUtils { + + + public static final String APP_KEY = SpringUtils.getRequiredProperty("face.appKey"); + public static final String APP_CODE = SpringUtils.getRequiredProperty("face.appCode"); + public static final String APP_SECRET = SpringUtils.getRequiredProperty("face.appSecret"); + + + /** + * 获取活体检测token + * @param returnUrl 前端跳转地址 + * @param colorLiveParam 自定义颜色,逗号分隔 + * @param actionLiveParam 自定义动作,逗号分隔 + */ + public static LivenessResponseTokenData getToken(String returnUrl, String colorLiveParam, String actionLiveParam) { + String host = "https://smkjhtjc.market.alicloudapi.com"; + String path = "/liveness/h5/token"; + String method = "GET"; + Map headers = new HashMap(); + //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105 + headers.put("Authorization", "APPCODE " + APP_CODE); + Map querys = new HashMap(); + querys.put("returnUrl", returnUrl); + querys.put("colorLiveParam", colorLiveParam); + querys.put("actionLiveParam", actionLiveParam); + + try { + HttpResponse res = AliHttpUtils.doGet(host, path, method, headers, querys); + LivenessResponseBody body = JSON.parseObject(EntityUtils.toString(res.getEntity()), LivenessResponseBody.class); + ServiceUtil.assertion(body.getCode() == null || !body.getCode().equals("200"), body.getMsg()); + return body.getData(); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } +} diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/valid/liveness/LivenessResponseBody.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/valid/liveness/LivenessResponseBody.java new file mode 100644 index 00000000..61d73016 --- /dev/null +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/valid/liveness/LivenessResponseBody.java @@ -0,0 +1,17 @@ +package com.ruoyi.common.valid.liveness; + +import lombok.Data; + +/** + * @author wjh + * 2024/9/20 + */ +@Data +public class LivenessResponseBody { + + private String msg; + private Boolean success; + private String code; + private T data; + +} diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/valid/liveness/LivenessResponseQueryData.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/valid/liveness/LivenessResponseQueryData.java new file mode 100644 index 00000000..7140a91c --- /dev/null +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/valid/liveness/LivenessResponseQueryData.java @@ -0,0 +1,21 @@ +package com.ruoyi.common.valid.liveness; + +import com.alibaba.fastjson2.annotation.JSONField; +import lombok.Data; + +/** + * @author wjh + * 2024/9/20 + */ +@Data +public class LivenessResponseQueryData { + + @JSONField(name = "order_no") + private String orderNo; + + private String token; + + private Integer result; //0通过;1不通过;2未找到活体检测结果 + + private String faceImage; +} diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/valid/liveness/LivenessResponseTokenData.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/valid/liveness/LivenessResponseTokenData.java new file mode 100644 index 00000000..60069218 --- /dev/null +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/valid/liveness/LivenessResponseTokenData.java @@ -0,0 +1,14 @@ +package com.ruoyi.common.valid.liveness; + +import lombok.Data; + +/** + * @author wjh + * 2024/9/20 + */ +@Data +public class LivenessResponseTokenData { + + private String token; + +} diff --git a/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/valid/liveness/LivenessUtils.java b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/valid/liveness/LivenessUtils.java new file mode 100644 index 00000000..e3e41267 --- /dev/null +++ b/smart-switch-ruoyi/smart-switch-common/src/main/java/com/ruoyi/common/valid/liveness/LivenessUtils.java @@ -0,0 +1,79 @@ +package com.ruoyi.common.valid.liveness; + +import com.alibaba.fastjson2.JSON; +import com.ruoyi.common.utils.ServiceUtil; +import com.ruoyi.common.utils.http.AliHttpUtils; +import com.ruoyi.common.utils.spring.SpringUtils; +import org.apache.http.HttpResponse; +import org.apache.http.util.EntityUtils; + +import java.util.HashMap; +import java.util.Map; + +/** + * 活体检测 + * https://market.aliyun.com/apimarket/detail/cmapi00064393?spm=5176.730005.result.10.2271414a01R1ZI#sku=yuncode5839300001 + * @author wjh + * 2024/9/20 + */ +public class LivenessUtils { + + public static final String APP_KEY = SpringUtils.getRequiredProperty("liveness.appKey"); + public static final String APP_CODE = SpringUtils.getRequiredProperty("liveness.appCode"); + public static final String APP_SECRET = SpringUtils.getRequiredProperty("liveness.appSecret"); + + + /** + * 获取活体检测token + * @param returnUrl 前端跳转地址 + * @param colorLiveParam 自定义颜色,逗号分隔 + * @param actionLiveParam 自定义动作,逗号分隔 + */ + public static LivenessResponseTokenData getToken(String returnUrl, String colorLiveParam, String actionLiveParam) { + String host = "https://smkjhtjc.market.alicloudapi.com"; + String path = "/liveness/h5/token"; + String method = "GET"; + Map headers = new HashMap(); + //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105 + headers.put("Authorization", "APPCODE " + APP_CODE); + Map querys = new HashMap(); + querys.put("returnUrl", returnUrl); + querys.put("colorLiveParam", colorLiveParam); + querys.put("actionLiveParam", actionLiveParam); + + try { + HttpResponse res = AliHttpUtils.doGet(host, path, method, headers, querys); + LivenessResponseBody body = JSON.parseObject(EntityUtils.toString(res.getEntity()), LivenessResponseBody.class); + ServiceUtil.assertion(body.getCode() == null || !body.getCode().equals("200"), body.getMsg()); + return body.getData(); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + + /** + * 查询活体检测结果 + */ + public static LivenessResponseQueryData queryResult(String token) { + String host = "https://smkjhtjc.market.alicloudapi.com"; + String path = "/liveness/h5/result"; + String method = "GET"; + Map headers = new HashMap(); + //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105 + headers.put("Authorization", "APPCODE " + APP_CODE); + Map querys = new HashMap(); + querys.put("token", token); + + try { + HttpResponse res = AliHttpUtils.doGet(host, path, method, headers, querys); + LivenessResponseBody body = JSON.parseObject(EntityUtils.toString(res.getEntity()), LivenessResponseBody.class); + ServiceUtil.assertion(body.getCode() == null || !body.getCode().equals("200"), body.getMsg()); + return body.getData(); + } catch (Exception e) { + e.printStackTrace(); + return null; + } + } + +} diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/service/impl/TransactionBillServiceImpl.java b/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/service/impl/TransactionBillServiceImpl.java index 335efa04..5e3c0591 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/service/impl/TransactionBillServiceImpl.java +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/transactionBill/service/impl/TransactionBillServiceImpl.java @@ -2,8 +2,10 @@ package com.ruoyi.ss.transactionBill.service.impl; import com.github.pagehelper.PageHelper; import com.ruoyi.common.constant.Constants; +import com.ruoyi.common.constant.HttpStatus; import com.ruoyi.common.core.redis.RedisLock; import com.ruoyi.common.core.redis.enums.RedisLockKey; +import com.ruoyi.common.enums.BusinessStatus; import com.ruoyi.common.enums.WithdrawServiceType; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.*; @@ -413,8 +415,8 @@ public class TransactionBillServiceImpl implements TransactionBillService, After AccountVO account = bo.getAccount(); ServiceUtil.assertion(user == null, "用户不存在"); - ServiceUtil.assertion(user.getIsReal() == null || !user.getIsReal(), "用户未实名认证,无法提现"); - ServiceUtil.assertion(user.getLimitWithdraw() != null && user.getLimitWithdraw(), "您被限制提现:" + user.getLimitWithdrawReason()); + ServiceUtil.assertion(user.getIsReal() == null || !user.getIsReal(), "用户未实名认证,无法提现", HttpStatus.NO_REAL_NAME); + ServiceUtil.assertion(user.getLimitWithdraw() != null && user.getLimitWithdraw(), "您被限制提现:" + user.getLimitWithdrawReason(), HttpStatus.LIMIT_WITHDRAW); // 判断今天提现成功和正在审核中的提现是否超过限额 String dailyLimitStr = sysConfigService.selectConfigByKey(ConfigKey.DAILY_WITHDRAW_AMOUNT.getKey()); diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/user/domain/dto/UserRealNameDTO.java b/smart-switch-service/src/main/java/com/ruoyi/ss/user/domain/dto/UserRealNameDTO.java index 55051cc7..bee5b36e 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/user/domain/dto/UserRealNameDTO.java +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/user/domain/dto/UserRealNameDTO.java @@ -34,4 +34,6 @@ public class UserRealNameDTO { @Pattern(regexp = RegexpUtils.MOBILE_PHONE_REGEXP, message = "手机号格式错误") private String realPhone; + private String faceReturnUrl; + } diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/user/domain/vo/UserRealNameVO.java b/smart-switch-service/src/main/java/com/ruoyi/ss/user/domain/vo/UserRealNameVO.java new file mode 100644 index 00000000..041944b2 --- /dev/null +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/user/domain/vo/UserRealNameVO.java @@ -0,0 +1,16 @@ +package com.ruoyi.ss.user.domain.vo; + +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +/** + * @author wjh + * 2024/9/20 + */ +@Data +public class UserRealNameVO { + + @ApiModelProperty("人脸识别token") + private String faceToken; + +} diff --git a/smart-switch-service/src/main/java/com/ruoyi/ss/user/service/impl/SmUserServiceImpl.java b/smart-switch-service/src/main/java/com/ruoyi/ss/user/service/impl/SmUserServiceImpl.java index 662d0792..d04b98c2 100644 --- a/smart-switch-service/src/main/java/com/ruoyi/ss/user/service/impl/SmUserServiceImpl.java +++ b/smart-switch-service/src/main/java/com/ruoyi/ss/user/service/impl/SmUserServiceImpl.java @@ -6,6 +6,7 @@ import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.ServiceUtil; import com.ruoyi.common.utils.collection.CollectionUtils; +import com.ruoyi.common.valid.liveness.LivenessUtils; import com.ruoyi.common.valid.realName.RealNameValidUtils; import com.ruoyi.ss.device.domain.DeviceQuery; import com.ruoyi.ss.device.domain.vo.DeviceVO; @@ -287,14 +288,19 @@ public class SmUserServiceImpl implements ISmUserService boolean check = RealNameValidUtils.validMobile3Info(dto.getRealIdCard(), dto.getRealPhone(), dto.getRealName()); ServiceUtil.assertion(!check, "请输入正确的身份信息:姓名、身份证、手机号需要一致"); + // 获取活体检测token + LivenessUtils.getToken(dto.getFaceReturnUrl(), ); + + // TODO 存入缓存 + // 修改实名信息 - SmUser data = new SmUserQuery(); - data.setUserId(dto.getUserId()); - data.setRealName(dto.getRealName()); - data.setRealIdCard(dto.getRealIdCard()); - data.setRealPhone(dto.getRealPhone()); - data.setIsReal(true); - return smUserMapper.updateSmUser(data); +// SmUser data = new SmUserQuery(); +// data.setUserId(dto.getUserId()); +// data.setRealName(dto.getRealName()); +// data.setRealIdCard(dto.getRealIdCard()); +// data.setRealPhone(dto.getRealPhone()); +// data.setIsReal(true); +// return smUserMapper.updateSmUser(data); } @Override diff --git a/smart-switch-web/src/main/java/com/ruoyi/web/controller/app/AppUserController.java b/smart-switch-web/src/main/java/com/ruoyi/web/controller/app/AppUserController.java index e988d191..5b06580f 100644 --- a/smart-switch-web/src/main/java/com/ruoyi/web/controller/app/AppUserController.java +++ b/smart-switch-web/src/main/java/com/ruoyi/web/controller/app/AppUserController.java @@ -72,7 +72,7 @@ public class AppUserController extends BaseController { @PutMapping("/realName") public AjaxResult realName(@RequestBody @Validated UserRealNameDTO dto) { dto.setUserId(getUserId()); - return toAjax(userService.realName(dto)); + return success(userService.realName(dto)); } @ApiOperation("标记用户已读商户协议") diff --git a/smart-switch-web/src/main/resources/application.yml b/smart-switch-web/src/main/resources/application.yml index 33cdc0c0..cf46890c 100644 --- a/smart-switch-web/src/main/resources/application.yml +++ b/smart-switch-web/src/main/resources/application.yml @@ -53,6 +53,17 @@ realName: appKey: 204590328 appCode: 32b6c6445b1a42ed862dd4202392c47d appSecret: td0vIGZRy9GxIrpfnIrxSXFXVW34JxDh +# 活体检测 +liveness: + appKey: 204590328 + appCode: 32b6c6445b1a42ed862dd4202392c47d + appSecret: td0vlGZRy9GxlrpinlrxSXFXVW34JxDh +# 人像比对 +face: + appKey: 204590328 + appCode: 32b6c6445b1a42ed862dd4202392c47d + appSecret: td0vlGZRy9GxlrpinlrxSXFXVW34JxDh + # 项目相关配置 ruoyi: @@ -151,7 +162,6 @@ lock: # 重试次数 retry: 3 - org: quartz: jobStore: