diff --git a/ebike-orders/pom.xml b/ebike-orders/pom.xml
index 94adc4bd..202cf685 100644
--- a/ebike-orders/pom.xml
+++ b/ebike-orders/pom.xml
@@ -180,6 +180,14 @@
org.springframework.boot
spring-boot-starter-actuator
+
+
+
+ com.cdp.product
+ cdp-common-security
+ 11.0.0-SNAPSHOT
+
+
diff --git a/ebike-orders/src/main/java/com/cdzy/orders/config/RealNameVerifyConfig.java b/ebike-orders/src/main/java/com/cdzy/orders/config/RealNameVerifyConfig.java
new file mode 100644
index 00000000..02a660fb
--- /dev/null
+++ b/ebike-orders/src/main/java/com/cdzy/orders/config/RealNameVerifyConfig.java
@@ -0,0 +1,34 @@
+package com.cdzy.orders.config;
+
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 实名认证配置类。
+ * 使用数据宝进行实名认证。
+ *
+ * @author dingchao
+ * @date 2025/5/29
+ * @modified by:
+ */
+@Getter
+@Setter
+@Configuration
+@ConfigurationProperties(prefix = "real-name")
+public class RealNameVerifyConfig {
+
+ /**
+ * 数据宝api序列号。
+ */
+ private String apiKey;
+ /**
+ * 数据宝客户端加密私钥。
+ */
+ private String clientPrivateKey;
+ /**
+ * 数据宝服务端加密公钥。
+ */
+ private String serverPublicKey;
+}
diff --git a/ebike-orders/src/main/java/com/cdzy/orders/config/WechatConfig.java b/ebike-orders/src/main/java/com/cdzy/orders/config/WechatConfig.java
index 1668bb54..869ae382 100644
--- a/ebike-orders/src/main/java/com/cdzy/orders/config/WechatConfig.java
+++ b/ebike-orders/src/main/java/com/cdzy/orders/config/WechatConfig.java
@@ -1,10 +1,8 @@
package com.cdzy.orders.config;
-import com.cdzy.orders.uitls.WechatUtil;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
diff --git a/ebike-orders/src/main/java/com/cdzy/orders/controller/EbikeUserController.java b/ebike-orders/src/main/java/com/cdzy/orders/controller/EbikeUserController.java
index f970c548..cab95f05 100644
--- a/ebike-orders/src/main/java/com/cdzy/orders/controller/EbikeUserController.java
+++ b/ebike-orders/src/main/java/com/cdzy/orders/controller/EbikeUserController.java
@@ -3,12 +3,13 @@ package com.cdzy.orders.controller;
import com.alibaba.fastjson2.JSONObject;
import com.cdzy.common.model.JsonResult;
import com.cdzy.orders.model.dto.req.ReqEbikeUserDto;
+import com.cdzy.orders.model.dto.req.ReqUserValidateDto;
import com.cdzy.orders.model.dto.req.ReqWechatInfoDto;
import com.cdzy.orders.model.dto.res.EbikeUserDto;
import com.cdzy.orders.model.entity.EbikeUser;
import com.cdzy.orders.model.entity.EbikeUserOrders;
import com.cdzy.orders.service.UserOrdersService;
-import com.cdzy.orders.uitls.WechatUtil;
+import com.cdzy.orders.uitls.VerifyUtil;
import com.mybatisflex.core.paginate.Page;
import jakarta.annotation.Resource;
import org.springframework.web.bind.annotation.*;
@@ -30,7 +31,7 @@ public class EbikeUserController {
@Autowired
private UserOrdersService userOrdersService;
@Resource
- private WechatUtil wechatUtil;
+ private VerifyUtil wechatUtil;
/**
* 用户微信无感登录。
@@ -73,6 +74,17 @@ public class EbikeUserController {
return JsonResult.success("解密成功", jsonObject.getString("phoneNumber"));
}
+ /**
+ * 验证用户实名
+ *
+ * @param reqUserValidateDto 验证用户实名请求
+ * @return 验证结果
+ */
+ @PostMapping("/verifyRealName")
+ public JsonResult> verifyRealName(@RequestBody ReqUserValidateDto reqUserValidateDto) {
+ return wechatUtil.verifyRealName(reqUserValidateDto);
+ }
+
/**
* 添加用户信息。
diff --git a/ebike-orders/src/main/java/com/cdzy/orders/model/dto/req/ReqUserValidateDto.java b/ebike-orders/src/main/java/com/cdzy/orders/model/dto/req/ReqUserValidateDto.java
new file mode 100644
index 00000000..f5fe4e16
--- /dev/null
+++ b/ebike-orders/src/main/java/com/cdzy/orders/model/dto/req/ReqUserValidateDto.java
@@ -0,0 +1,33 @@
+package com.cdzy.orders.model.dto.req;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 用户实名验证dto
+ *
+ * @author dingchao
+ * @date 2025/5/27
+ * @modified by:
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class ReqUserValidateDto implements Serializable {
+ /**
+ * 用户id
+ */
+ private String userId;
+ /**
+ * 姓名
+ */
+ private String name;
+ /**
+ * 身份证号
+ */
+ private String idCard;
+
+}
diff --git a/ebike-orders/src/main/java/com/cdzy/orders/uitls/VerifyUtil.java b/ebike-orders/src/main/java/com/cdzy/orders/uitls/VerifyUtil.java
new file mode 100644
index 00000000..b5fbd931
--- /dev/null
+++ b/ebike-orders/src/main/java/com/cdzy/orders/uitls/VerifyUtil.java
@@ -0,0 +1,218 @@
+package com.cdzy.orders.uitls;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.cdp.product.security.context.SecurityContext;
+import com.cdp.product.security.exception.DecryptFailureException;
+import com.cdp.product.security.exception.EncryptFailureException;
+import com.cdp.product.security.exception.SignFailureException;
+import com.cdp.product.security.strategyImpl.RSAStrategyImpl;
+import com.cdzy.common.model.JsonResult;
+import com.cdzy.orders.config.RealNameVerifyConfig;
+import com.cdzy.orders.config.WechatConfig;
+import com.cdzy.orders.model.dto.req.ReqUserValidateDto;
+import com.cdzy.orders.model.entity.EbikeUser;
+import com.cdzy.orders.service.EbikeUserService;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.*;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.springframework.stereotype.Service;
+
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.IvParameterSpec;
+import javax.crypto.spec.SecretKeySpec;
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.security.*;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.StringJoiner;
+
+/**
+ * 验证工具类
+ *
+ * @author dingchao
+ * @date 2025/4/9
+ * @modified by:
+ */
+@Slf4j
+@Service
+public class VerifyUtil {
+ /**
+ * 微信登录API地址
+ */
+ private static final String WECHAT_LOGIN_URL = "https://api.weixin.qq.com/sns/jscode2session";
+
+ /**
+ * 数据宝实名认证API地址
+ */
+ private static final String REALNAME_VERIFY_URL = "https://api.chinadatapay.com/communication/personal/1882";
+
+ /**
+ * OkHttpClient实例
+ */
+ private static OkHttpClient client = null;
+
+ @Resource
+ private WechatConfig wechatConfig;
+ @Resource
+ private RealNameVerifyConfig realNameVerifyConfig;
+ @Resource
+ private EbikeUserService ebikeUserService;
+
+ /**
+ * 微信工具类构造函数。
+ *
+ */
+ public VerifyUtil() throws IOException {
+ client = new OkHttpClient();
+ }
+
+ /**
+ * 获取openId。
+ *
+ * @param code 微信登录返回的code
+ * @return openId
+ */
+ public JSONObject wechatAuthority(String code){
+ Map params = new HashMap<>();
+ params.put("appid", wechatConfig.getAppId());
+ params.put("secret", wechatConfig.getAppSecret());
+ params.put("js_code", code);
+ params.put("grant_type", "authorization_code");
+ return httpGet("获取openId", WECHAT_LOGIN_URL, params);
+ }
+
+ /**
+ * 解密微信用户信息。
+ *
+ * @param encryptedData 加密数据
+ * @param sessionKey 会话密钥
+ * @param iv 初始向量
+ * @return 解密后的用户信息
+ */
+ public String decryptData(String encryptedData, String sessionKey, String iv) {
+ try {
+ // 添加 BouncyCastle 安全提供器
+ Security.addProvider(new BouncyCastleProvider());
+
+ // Base64 解码参数
+ byte[] encryptedBytes = Base64.getDecoder().decode(encryptedData);
+ byte[] sessionKeyBytes = Base64.getDecoder().decode(sessionKey);
+ byte[] ivBytes = Base64.getDecoder().decode(iv);
+
+ // 初始化 AES-CBC 解密器
+ SecretKeySpec keySpec = new SecretKeySpec(sessionKeyBytes, "AES");
+ IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
+ Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
+ cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
+
+ // 执行解密
+ byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
+ return new String(decryptedBytes, StandardCharsets.UTF_8);
+ } catch (Exception e) {
+ log.error("解密失败", e);
+ return null;
+ }
+ }
+
+ /**
+ * 验证用户实名
+ *
+ * @param reqUserValidateDto 验证用户实名请求
+ * @return 验证结果
+ */
+ public JsonResult> verifyRealName(ReqUserValidateDto reqUserValidateDto) {
+ EbikeUser ebikeUser = ebikeUserService.getById(reqUserValidateDto.getUserId());
+ if (ebikeUser == null) {
+ log.error("用户不存在");
+ return JsonResult.failed("用户不存在");
+ }
+ try {
+ SecurityContext securityContext = new SecurityContext();
+ //设置加解密上下⽂类调⽤RSA加解密类
+ securityContext.setSecurityImpl(new RSAStrategyImpl());
+ //设置加解密上下⽂类调⽤RSA加解密类加签
+ securityContext.setSign(new RSAStrategyImpl());
+
+ // 1. 加密数据
+ Map params = new HashMap<>();
+ params.put("name", securityContext.encrypt(reqUserValidateDto.getName(), realNameVerifyConfig.getServerPublicKey()));
+ params.put("idcard", securityContext.encrypt(reqUserValidateDto.getIdCard(), realNameVerifyConfig.getServerPublicKey()));
+ params.put("timestamp", securityContext.encrypt(String.valueOf(System.currentTimeMillis()), realNameVerifyConfig.getServerPublicKey()));
+ String sign = securityContext.sign(params, realNameVerifyConfig.getClientPrivateKey());
+ params.put("sign", sign);
+ params.put("key", realNameVerifyConfig.getApiKey());
+
+ // 2. 验证用户实名
+ JSONObject result = httpGet("验证用户实名", REALNAME_VERIFY_URL, params);
+ if (result == null) {
+ log.error("验证用户实名失败");
+ return JsonResult.failed("验证用户实名失败");
+ }
+ if ("10000".equals(result.getString("code"))){
+ // 3. 解密结果
+ String data = securityContext.decrypt(result.getString("data"), realNameVerifyConfig.getClientPrivateKey());
+ JSONObject jsonData = JSON.parseObject(data);
+ if("10000".equals(jsonData.getString("code"))&&"1".equals(jsonData.getJSONObject("data").getString("state"))){
+ // 4. 更新用户实名信息
+
+ return JsonResult.success("验证用户实名成功");
+ }
+ }else{
+ log.error("验证用户实名失败,{} {}", result.getString("code"), result.getString("message"));
+ return JsonResult.failed(result.getString("code") +", "+ result.getString("message"));
+ }
+ }catch (EncryptFailureException e) {
+ log.error("加密失败", e);
+ return JsonResult.failed("加密失败");
+ }catch (SignFailureException e) {
+ log.error("签名失败", e);
+ return JsonResult.failed("签名失败");
+ } catch (DecryptFailureException e) {
+ log.error("结果解密失败", e);
+ return JsonResult.failed("结果解密失败");
+ }
+ }
+
+ /**
+ * 发送HTTP GET请求。
+ *
+ * @param func_ 功能描述
+ * @param url 请求URL
+ * @param params 请求参数
+ * @return 响应结果
+ */
+ private JSONObject httpGet(String func_, String url, Map params) {
+ StringJoiner paramJoiner = new StringJoiner("&");
+ for (Map.Entry entry : params.entrySet()) {
+ paramJoiner.add(entry.getKey() + "=" + entry.getValue());
+ }
+ String requestUrl = url + "?" + paramJoiner.toString();
+ Request request = new Request.Builder()
+ .url(requestUrl)
+ .method("GET", null)
+ .build();
+ try (Response response = client.newCall(request).execute()) {
+ if (response.isSuccessful()) {
+ if (response.body() != null) {
+ return JSON.parseObject(response.body().string());
+ }
+ log.error("{}, 请求{}无返回结果", func_, url);
+ return null;
+ }
+ if (response.body() != null) {
+ log.error("{}, 请求{}失败, {}", func_, url, response.body().string());
+ }else {
+ log.error("{}, 请求{}失败", func_, url);
+ }
+ return null;
+ } catch (Exception e) {
+ log.error("{}, 请求{}失败", func_, url, e);
+ return null;
+ }
+ }
+}
diff --git a/ebike-orders/src/main/java/com/cdzy/orders/uitls/WechatUtil.java b/ebike-orders/src/main/java/com/cdzy/orders/uitls/WechatUtil.java
deleted file mode 100644
index d413f626..00000000
--- a/ebike-orders/src/main/java/com/cdzy/orders/uitls/WechatUtil.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package com.cdzy.orders.uitls;
-
-import com.alibaba.fastjson2.JSONObject;
-import com.cdzy.orders.config.WechatConfig;
-import jakarta.annotation.Resource;
-import lombok.extern.slf4j.Slf4j;
-import okhttp3.*;
-import org.bouncycastle.jce.provider.BouncyCastleProvider;
-import org.springframework.stereotype.Service;
-
-
-import javax.crypto.Cipher;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-import java.io.*;
-import java.nio.charset.StandardCharsets;
-import java.security.*;
-import java.util.Base64;
-
-/**
- * 微信工具类
- *
- * @author dingchao
- * @date 2025/4/9
- * @modified by:
- */
-@Slf4j
-@Service
-public class WechatUtil {
- /**
- * 微信登录API地址
- */
- private static final String WECHAT_LOGIN_URL = "https://api.weixin.qq.com/sns/jscode2session";
-
- /**
- * OkHttpClient实例
- */
- private static OkHttpClient client = null;
-
- @Resource
- private WechatConfig wechatConfig;
-
- /**
- * 微信工具类构造函数。
- *
- */
- public WechatUtil() throws IOException {
- client = new OkHttpClient();
- }
-
- /**
- * 获取openId。
- *
- * @param code 微信登录返回的code
- * @return openId
- */
- public JSONObject wechatAuthority(String code){
- Request request = new Request.Builder()
- .url(WECHAT_LOGIN_URL + "?appid=" + wechatConfig.getAppId() + "&secret=" + wechatConfig.getAppSecret() + "&js_code=" + code + "&grant_type=authorization_code")
- .build();
- try(Response response = client.newCall(request).execute()) {
- if(response.isSuccessful()) {
- if (response.body()!= null) {
- String result = response.body().string();
- JSONObject jsonObject = JSONObject.parseObject(result);
- log.info("result: {}", jsonObject);
- return jsonObject;
- }
- log.error("获取openId失败");
- return null;
- }
- log.error("获取openId失败");
- return null;
- }catch (IOException e){
- log.error("获取openId失败", e);
- return null;
- }
- }
-
- /**
- * 解密微信用户信息。
- *
- * @param encryptedData 加密数据
- * @param sessionKey 会话密钥
- * @param iv 初始向量
- * @return 解密后的用户信息
- */
- public String decryptData(String encryptedData, String sessionKey, String iv) {
- try {
- // 添加 BouncyCastle 安全提供器
- Security.addProvider(new BouncyCastleProvider());
-
- // Base64 解码参数
- byte[] encryptedBytes = Base64.getDecoder().decode(encryptedData);
- byte[] sessionKeyBytes = Base64.getDecoder().decode(sessionKey);
- byte[] ivBytes = Base64.getDecoder().decode(iv);
-
- // 初始化 AES-CBC 解密器
- SecretKeySpec keySpec = new SecretKeySpec(sessionKeyBytes, "AES");
- IvParameterSpec ivSpec = new IvParameterSpec(ivBytes);
- Cipher cipher = Cipher.getInstance("AES/CBC/PKCS7Padding", "BC");
- cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
-
- // 执行解密
- byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
- return new String(decryptedBytes, StandardCharsets.UTF_8);
- } catch (Exception e) {
- throw new RuntimeException("解密失败", e);
- }
- }
-
-}
diff --git a/ebike-orders/src/main/resources/application-dev.yml b/ebike-orders/src/main/resources/application-dev.yml
index 3fe773a3..900800a5 100644
--- a/ebike-orders/src/main/resources/application-dev.yml
+++ b/ebike-orders/src/main/resources/application-dev.yml
@@ -7,7 +7,7 @@ spring:
name: ebike-orders
cloud:
nacos:
- server-addr: 192.168.2.226:8848 # nacos
+ server-addr: 127.0.0.1:8848 # nacos
username: nacos
password: nacos
jackson:
@@ -92,7 +92,10 @@ minio:
access-key: eQtGmQBEsGxNHrTd7AkJ # 访问密钥
secret-key: Zg6X6j0kgUT1fGsGSgoCZWu6fgL8F3Kw1FfoX4yJ # 私有密钥
bucket-name: test
-
+real-name:
+ api-key: 123456789
+ client-private-pey: 123456789
+ server-public-key: 123456789
management:
endpoints:
web:
diff --git a/ebike-payment/src/main/java/com/cdzy/payment/controller/EbikeWxPaymentController.java b/ebike-payment/src/main/java/com/cdzy/payment/controller/EbikeWxPaymentController.java
index bd4a967a..d1d738cf 100644
--- a/ebike-payment/src/main/java/com/cdzy/payment/controller/EbikeWxPaymentController.java
+++ b/ebike-payment/src/main/java/com/cdzy/payment/controller/EbikeWxPaymentController.java
@@ -202,7 +202,7 @@ public class EbikeWxPaymentController {
/**
* 退款申请用户交易记录
*
- * @param reqTradeRecordDto
+ * @param reqTradeRecordDto 查询条件
* @return
*/
@PostMapping("/refundApplyTradeRecord")
@@ -214,7 +214,7 @@ public class EbikeWxPaymentController {
/**
* 退款申请用户退款记录
*
- * @param reqRefundRecordDto
+ * @param reqRefundRecordDto 查询条件
* @return
*/
@PostMapping("/refundApplyRefundRecord")
diff --git a/ebike-payment/src/main/java/com/cdzy/payment/service/WxPayService.java b/ebike-payment/src/main/java/com/cdzy/payment/service/WxPayService.java
index 0acbe431..40136b3a 100644
--- a/ebike-payment/src/main/java/com/cdzy/payment/service/WxPayService.java
+++ b/ebike-payment/src/main/java/com/cdzy/payment/service/WxPayService.java
@@ -20,6 +20,7 @@ import javax.servlet.http.HttpServletRequest;
* @modified by:
*/
public interface WxPayService {
+
/**
* 关闭订单
*
diff --git a/ebike-payment/src/main/java/com/cdzy/payment/service/impl/WxPayServiceImpl.java b/ebike-payment/src/main/java/com/cdzy/payment/service/impl/WxPayServiceImpl.java
index 7be43c6c..497a1ea7 100644
--- a/ebike-payment/src/main/java/com/cdzy/payment/service/impl/WxPayServiceImpl.java
+++ b/ebike-payment/src/main/java/com/cdzy/payment/service/impl/WxPayServiceImpl.java
@@ -17,6 +17,7 @@ import com.cdzy.payment.model.enums.RefoundApplySource;
import com.cdzy.payment.model.enums.RefundProcessState;
import com.cdzy.payment.service.EbikePaymentService;
import com.cdzy.payment.service.EbikeRefundService;
+import com.cdzy.payment.service.EbikeUserService;
import com.cdzy.payment.service.WxPayService;
import com.cdzy.payment.utils.HttpServletUtils;
import com.cdzy.payment.utils.MapUtils;
@@ -85,6 +86,8 @@ public class WxPayServiceImpl implements WxPayService {
@Resource
private EbikeRefundService ebikeRefundService;
@Resource
+ private EbikeUserService ebikeUserService;
+ @Resource
private OrdersFeignClient ordersFeignClient;
@Resource
private MaintenanceFeignClient maintenanceFeignClient;
diff --git a/ebike-payment/src/main/resources/application-dev.yml b/ebike-payment/src/main/resources/application-dev.yml
index 73df8bd3..16d0308d 100644
--- a/ebike-payment/src/main/resources/application-dev.yml
+++ b/ebike-payment/src/main/resources/application-dev.yml
@@ -66,9 +66,6 @@ task-scheduler-pool:
threadNamePrefix: task-scheduled-
waitForTasksToCompleteOnShutdown: true
awaitTerminationSeconds: 30
-geo-coding:
- api-url: https://apis.map.qq.com/ws/geocoder/v1
- access-key: BECBZ-EJIEQ-LUU5N-B5ISQ-3TLMZ-BXFLG
management:
endpoints: