From 1032ab5933532ee88af6693a2070e64c1c948d22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A2=81=E5=AE=87=E5=A5=87?= Date: Thu, 20 Nov 2025 23:53:39 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=A1=A3=E5=8F=A3=E8=AE=A4?= =?UTF-8?q?=E8=AF=81=E6=97=B6=E4=BD=BF=E7=94=A8=E7=9A=84=E7=AC=AC=E4=B8=89?= =?UTF-8?q?=E6=96=B9=E6=8E=A5=E5=8F=A3=E3=80=81=E7=9F=AD=E4=BF=A1=E9=AA=8C?= =?UTF-8?q?=E8=AF=81=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ruoyi/common/constant/CacheConstants.java | 6 + .../com/ruoyi/xkt/service/IStoreService.java | 15 + .../xkt/service/impl/StoreServiceImpl.java | 21 ++ .../ruoyi/xkt/thirdpart/lfv2/Lfv2Client.java | 108 ++++++ .../xkt/thirdpart/lfv2/Lfv2HttpUtil.java | 318 ++++++++++++++++++ 5 files changed, 468 insertions(+) create mode 100644 xkt/src/main/java/com/ruoyi/xkt/thirdpart/lfv2/Lfv2Client.java create mode 100644 xkt/src/main/java/com/ruoyi/xkt/thirdpart/lfv2/Lfv2HttpUtil.java diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java index 65e128e59..10b381116 100644 --- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java +++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java @@ -32,12 +32,18 @@ public class CacheConstants { */ public static final String SMS_ASSET_CAPTCHA_CODE_KEY = "sms_asset_captcha_codes:"; + /** + * 档口认证验证码 + */ + public static final String SMS_STORE_AUTH_CAPTCHA_CODE_KEY = "sms_store_auth_captcha_codes:"; + /** * 短信验证码CD中号码 */ public static final String SMS_ASSET_CAPTCHA_CODE_CD_PHONE_NUM_KEY = "sms_asset_captcha_code_cd_phone_nums:"; public static final String SMS_LOGIN_CAPTCHA_CODE_CD_PHONE_NUM_KEY = "sms_login_captcha_code_cd_phone_nums:"; public static final String SMS_REGISTER_CAPTCHA_CODE_CD_PHONE_NUM_KEY = "sms_register_captcha_code_cd_phone_nums:"; + public static final String SMS_STORE_AUTH_CAPTCHA_CODE_CD_PHONE_NUM_KEY = "sms_store_auth_captcha_code_cd_phone_nums:"; /** * 扫码登录浏览器ID diff --git a/xkt/src/main/java/com/ruoyi/xkt/service/IStoreService.java b/xkt/src/main/java/com/ruoyi/xkt/service/IStoreService.java index 34ada6ca1..ce6ebc19b 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/service/IStoreService.java +++ b/xkt/src/main/java/com/ruoyi/xkt/service/IStoreService.java @@ -224,4 +224,19 @@ public interface IStoreService { */ Integer UpdateSpecialAttr(StoreUpdateSpecialDTO specialDTO); + /** + * 发短信验证码(档口认证) + * + * @param phoneNumber + */ + void sendSmsVerificationCode(String phoneNumber); + + /** + * 验证短信验证码(档口认证) + * + * @param phoneNumber + * @param code + */ + void validateSmsVerificationCode(String phoneNumber, String code); + } diff --git a/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreServiceImpl.java b/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreServiceImpl.java index 562bfd7dd..d67da9b3f 100644 --- a/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreServiceImpl.java +++ b/xkt/src/main/java/com/ruoyi/xkt/service/impl/StoreServiceImpl.java @@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.RandomUtil; import co.elastic.clients.elasticsearch.core.BulkResponse; import co.elastic.clients.elasticsearch.core.bulk.BulkOperation; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; @@ -21,6 +22,7 @@ import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.bigDecimal.CollectorsUtil; import com.ruoyi.framework.es.EsClientWrapper; +import com.ruoyi.framework.sms.SmsClientWrapper; import com.ruoyi.system.mapper.SysUserMapper; import com.ruoyi.system.service.ISysUserService; import com.ruoyi.xkt.domain.*; @@ -81,6 +83,7 @@ public class StoreServiceImpl implements IStoreService { final StoreCustomerMapper storeCusMapper; final StoreFactoryMapper storeFactoryMapper; final IStoreProductDemandTemplateService storeTemplateService; + final SmsClientWrapper smsClient; @Value("${es.indexName}") private String ES_INDEX_NAME; @@ -596,6 +599,24 @@ public class StoreServiceImpl implements IStoreService { return this.storeMapper.updateById(store); } + @Transactional(readOnly = true) + @Override + public void sendSmsVerificationCode(String phoneNumber) { + boolean success = smsClient.sendVerificationCode(CacheConstants.SMS_STORE_AUTH_CAPTCHA_CODE_CD_PHONE_NUM_KEY, + CacheConstants.SMS_STORE_AUTH_CAPTCHA_CODE_KEY, phoneNumber, RandomUtil.randomNumbers(6)); + if (!success) { + throw new ServiceException("短信发送失败"); + } + } + + @Transactional(readOnly = true) + @Override + public void validateSmsVerificationCode(String phoneNumber, String code) { + boolean match = smsClient.matchVerificationCode(CacheConstants.SMS_STORE_AUTH_CAPTCHA_CODE_KEY, phoneNumber, code); + if (!match) { + throw new ServiceException("验证码错误或已过期"); + } + } /** * 档口首页今日销售额 diff --git a/xkt/src/main/java/com/ruoyi/xkt/thirdpart/lfv2/Lfv2Client.java b/xkt/src/main/java/com/ruoyi/xkt/thirdpart/lfv2/Lfv2Client.java new file mode 100644 index 000000000..2ef306eed --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/thirdpart/lfv2/Lfv2Client.java @@ -0,0 +1,108 @@ +package com.ruoyi.xkt.thirdpart.lfv2; + +import cn.hutool.core.map.MapUtil; +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpUtil; +import cn.hutool.json.JSONObject; +import cn.hutool.json.JSONUtil; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author liangyq + * @date 2025-11-20 + */ +@Slf4j +@Component +public class Lfv2Client { + + private static final String ENT4URL = "https://swent4.market.alicloudapi.com/verify/enterprise4"; + + private static final String PHONE3URL = "https://swphone3.market.alicloudapi.com/verify/operator3_precision"; + + @Value("${lfv2.auth:APPCODE 4dd403cda2694a45a1124b09637612b6}") + private String authCode; + + /** + * 检查企业四要素 + * + * @param creditCode 社会统一信用代码 + * @param enterpriseName 企业名 + * @param legalPersonName 法人名称 + * @param legalIdNumber 法人身份证号 + * @return + */ + public boolean checkEnterprise(String creditCode, String enterpriseName, String legalPersonName, + String legalIdNumber) { + Map headers = new HashMap<>(); + //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105 + headers.put("Authorization", authCode); + //根据API的要求,定义相对应的Content-Type + headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); + Map body = new HashMap<>(); + body.put("credit_code", creditCode); + body.put("enterprise_name", enterpriseName); + body.put("legal_person_name", legalPersonName); + body.put("legal_id_number", legalIdNumber); + try { + String response = httpPost(ENT4URL, headers, body); + log.info("企业四要素接口: {}, {}", body, response); + JSONObject result = JSONUtil.parseObj(response).getJSONObject("result"); + Integer r1 = result.getInt("enterprise_name_match"); + Integer r2 = result.getInt("credit_code_match"); + Integer r3 = result.getInt("legal_person_name_match"); + Integer r4 = result.getInt("legal_id_number_match"); + return Integer.valueOf(1).equals(r1) + && Integer.valueOf(1).equals(r2) + && Integer.valueOf(1).equals(r3) + && Integer.valueOf(1).equals(r4); + } catch (Exception e) { + log.error("企业四要素接口异常", e); + } + return false; + } + + /** + * 检查手机号三要素 + * + * @param phoneNumber 手机号 + * @param personName 姓名 + * @param idNumber 身份证号 + * @return + */ + public boolean checkPhone(String phoneNumber, String personName, String idNumber) { + Map headers = new HashMap<>(); + //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105 + headers.put("Authorization", authCode); + //根据API的要求,定义相对应的Content-Type + headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); + Map body = new HashMap<>(); + body.put("name", personName); + body.put("id_number", idNumber); + body.put("phone_number", phoneNumber); + try { + String response = httpPost(PHONE3URL, headers, body); + log.info("手机号三要素接口: {}, {}", body, response); + Integer checkResult = JSONUtil.parseObj(response).getByPath("result.checkresult", Integer.class); + return Integer.valueOf(1).equals(checkResult); + } catch (Exception e) { + log.error("手机号三要素接口异常", e); + } + return false; + } + + private String httpPost(String url, Map headers, Map body) { + HttpRequest httpRequest = HttpUtil.createPost(url); + if (MapUtil.isNotEmpty(headers)) { + httpRequest.addHeaders(headers); + } + if (MapUtil.isNotEmpty(body)) { + httpRequest.formStr(body); + } + return httpRequest.execute().body(); + } +} diff --git a/xkt/src/main/java/com/ruoyi/xkt/thirdpart/lfv2/Lfv2HttpUtil.java b/xkt/src/main/java/com/ruoyi/xkt/thirdpart/lfv2/Lfv2HttpUtil.java new file mode 100644 index 000000000..e12d59e71 --- /dev/null +++ b/xkt/src/main/java/com/ruoyi/xkt/thirdpart/lfv2/Lfv2HttpUtil.java @@ -0,0 +1,318 @@ +package com.ruoyi.xkt.thirdpart.lfv2; + +import cn.hutool.core.util.StrUtil; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.HttpClient; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.conn.ClientConnectionManager; +import org.apache.http.conn.scheme.Scheme; +import org.apache.http.conn.scheme.SchemeRegistry; +import org.apache.http.conn.ssl.SSLSocketFactory; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.DefaultHttpClient; +import org.apache.http.message.BasicNameValuePair; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.TrustManager; +import javax.net.ssl.X509TrustManager; +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.security.KeyManagementException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + +/** + * @author liangyq + * @date 2025-11-20 + */ +public class Lfv2HttpUtil { + /** + * get + * + * @param host + * @param path + * @param method + * @param headers + * @param querys + * @return + * @throws Exception + */ + public static HttpResponse doGet(String host, String path, String method, + Map headers, + Map querys) + throws Exception { + HttpClient httpClient = wrapClient(host); + + HttpGet request = new HttpGet(buildUrl(host, path, querys)); + for (Map.Entry e : headers.entrySet()) { + request.addHeader(e.getKey(), e.getValue()); + } + + return httpClient.execute(request); + } + + /** + * post form + * + * @param host + * @param path + * @param method + * @param headers + * @param querys + * @param bodys + * @return + * @throws Exception + */ + public static HttpResponse doPost(String host, String path, String method, + Map headers, + Map querys, + Map bodys) + throws Exception { + HttpClient httpClient = wrapClient(host); + + HttpPost request = new HttpPost(buildUrl(host, path, querys)); + for (Map.Entry e : headers.entrySet()) { + request.addHeader(e.getKey(), e.getValue()); + } + + if (bodys != null) { + List nameValuePairList = new ArrayList(); + + for (String key : bodys.keySet()) { + nameValuePairList.add(new BasicNameValuePair(key, bodys.get(key))); + } + UrlEncodedFormEntity formEntity = new UrlEncodedFormEntity(nameValuePairList, "utf-8"); + formEntity.setContentType("application/x-www-form-urlencoded; charset=UTF-8"); + request.setEntity(formEntity); + } + + return httpClient.execute(request); + } + + /** + * Post String + * + * @param host + * @param path + * @param method + * @param headers + * @param querys + * @param body + * @return + * @throws Exception + */ + public static HttpResponse doPost(String host, String path, String method, + Map headers, + Map querys, + String body) + throws Exception { + HttpClient httpClient = wrapClient(host); + + HttpPost request = new HttpPost(buildUrl(host, path, querys)); + for (Map.Entry e : headers.entrySet()) { + request.addHeader(e.getKey(), e.getValue()); + } + + if (StrUtil.isNotBlank(body)) { + request.setEntity(new StringEntity(body, "utf-8")); + } + + return httpClient.execute(request); + } + + /** + * Post stream + * + * @param host + * @param path + * @param method + * @param headers + * @param querys + * @param body + * @return + * @throws Exception + */ + public static HttpResponse doPost(String host, String path, String method, + Map headers, + Map querys, + byte[] body) + throws Exception { + HttpClient httpClient = wrapClient(host); + + HttpPost request = new HttpPost(buildUrl(host, path, querys)); + for (Map.Entry e : headers.entrySet()) { + request.addHeader(e.getKey(), e.getValue()); + } + + if (body != null) { + request.setEntity(new ByteArrayEntity(body)); + } + + return httpClient.execute(request); + } + + /** + * Put String + * + * @param host + * @param path + * @param method + * @param headers + * @param querys + * @param body + * @return + * @throws Exception + */ + public static HttpResponse doPut(String host, String path, String method, + Map headers, + Map querys, + String body) + throws Exception { + HttpClient httpClient = wrapClient(host); + + HttpPut request = new HttpPut(buildUrl(host, path, querys)); + for (Map.Entry e : headers.entrySet()) { + request.addHeader(e.getKey(), e.getValue()); + } + + if (StrUtil.isNotBlank(body)) { + request.setEntity(new StringEntity(body, "utf-8")); + } + + return httpClient.execute(request); + } + + /** + * Put stream + * + * @param host + * @param path + * @param method + * @param headers + * @param querys + * @param body + * @return + * @throws Exception + */ + public static HttpResponse doPut(String host, String path, String method, + Map headers, + Map querys, + byte[] body) + throws Exception { + HttpClient httpClient = wrapClient(host); + + HttpPut request = new HttpPut(buildUrl(host, path, querys)); + for (Map.Entry e : headers.entrySet()) { + request.addHeader(e.getKey(), e.getValue()); + } + + if (body != null) { + request.setEntity(new ByteArrayEntity(body)); + } + + return httpClient.execute(request); + } + + /** + * Delete + * + * @param host + * @param path + * @param method + * @param headers + * @param querys + * @return + * @throws Exception + */ + public static HttpResponse doDelete(String host, String path, String method, + Map headers, + Map querys) + throws Exception { + HttpClient httpClient = wrapClient(host); + + HttpDelete request = new HttpDelete(buildUrl(host, path, querys)); + for (Map.Entry e : headers.entrySet()) { + request.addHeader(e.getKey(), e.getValue()); + } + + return httpClient.execute(request); + } + + private static String buildUrl(String host, String path, Map querys) throws UnsupportedEncodingException { + StringBuilder sbUrl = new StringBuilder(); + sbUrl.append(host); + if (!StrUtil.isBlank(path)) { + sbUrl.append(path); + } + if (null != querys) { + StringBuilder sbQuery = new StringBuilder(); + for (Map.Entry query : querys.entrySet()) { + if (0 < sbQuery.length()) { + sbQuery.append("&"); + } + if (StrUtil.isBlank(query.getKey()) && !StrUtil.isBlank(query.getValue())) { + sbQuery.append(query.getValue()); + } + if (!StrUtil.isBlank(query.getKey())) { + sbQuery.append(query.getKey()); + if (!StrUtil.isBlank(query.getValue())) { + sbQuery.append("="); + sbQuery.append(URLEncoder.encode(query.getValue(), "utf-8")); + } + } + } + if (0 < sbQuery.length()) { + sbUrl.append("?").append(sbQuery); + } + } + + return sbUrl.toString(); + } + + private static HttpClient wrapClient(String host) { + HttpClient httpClient = new DefaultHttpClient(); + if (host.startsWith("https://")) { + sslClient(httpClient); + } + + return httpClient; + } + + private static void sslClient(HttpClient httpClient) { + try { + SSLContext ctx = SSLContext.getInstance("TLS"); + X509TrustManager tm = new X509TrustManager() { + public X509Certificate[] getAcceptedIssuers() { + return null; + } + + public void checkClientTrusted(X509Certificate[] xcs, String str) { + + } + + public void checkServerTrusted(X509Certificate[] xcs, String str) { + + } + }; + ctx.init(null, new TrustManager[]{tm}, null); + SSLSocketFactory ssf = new SSLSocketFactory(ctx); + ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); + ClientConnectionManager ccm = httpClient.getConnectionManager(); + SchemeRegistry registry = ccm.getSchemeRegistry(); + registry.register(new Scheme("https", 443, ssf)); + } catch (KeyManagementException ex) { + throw new RuntimeException(ex); + } catch (NoSuchAlgorithmException ex) { + throw new RuntimeException(ex); + } + } +}