1
0

2 Ревизии 700318edfa ... 86b1fc4fa8

Автор SHA1 Съобщение Дата
  csy 86b1fc4fa8 Merge remote-tracking branch 'origin/master_exclusive_shop_20250718' into master_exclusive_shop_20250718 преди 2 седмици
  csy 8cdf387c34 手机加密 преди 3 седмици

+ 8 - 0
fs-service-system/src/main/java/com/fs/store/service/channel/TzbkPaymentHandler.java

@@ -27,7 +27,10 @@ import org.springframework.transaction.interceptor.TransactionAspectSupport;
 import java.text.SimpleDateFormat;
 import java.time.Instant;
 import java.util.Date;
+import java.util.regex.Pattern;
 
+import static com.fs.until.PhoneUtil.decryptPhone;
+import static com.fs.until.PhoneUtil.encryptPhone;
 import static org.springframework.beans.factory.config.ConfigurableBeanFactory.SCOPE_PROTOTYPE;
 
 /**
@@ -67,6 +70,11 @@ public class TzbkPaymentHandler extends PaymentHandler{
         reqBodyDTO.setPayNotifyUrl(tzConfigInfoDTO.getPayNotifyUrl());
         reqBodyDTO.setPayerName(user.getUsername());
         reqBodyDTO.setPayerMobileNo(user.getPhone());
+        Pattern PHONE_PATTERN = Pattern.compile("^1\\d{10}$");
+        if (PHONE_PATTERN.matcher(user.getPhone().trim()).matches()){
+            reqBodyDTO.setPayerMobileNo(decryptPhone(user.getPhone()));
+            log.info("创建台州订单电话解密:{}" , reqBodyDTO.getPayerMobileNo());
+        }
         reqBodyDTO.setGoodsInfo(context.getGoodsInfo());
         // 不需要分账
         reqBodyDTO.setNeedLedger("00");

+ 17 - 0
fs-service-system/src/main/java/com/fs/store/service/impl/FsUserServiceImpl.java

@@ -5,6 +5,7 @@ import java.math.BigDecimal;
 import java.util.*;
 import java.util.concurrent.CompletableFuture;
 import java.util.function.Function;
+import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
 import cn.binarywang.wx.miniapp.api.WxMaService;
@@ -74,6 +75,8 @@ import javax.annotation.PostConstruct;
 
 import static com.fs.store.enums.BillDetailEnum.CATEGORY_1;
 import static com.fs.store.enums.BillDetailEnum.CATEGORY_3;
+import static com.fs.until.PhoneUtil.decryptPhone;
+import static com.fs.until.PhoneUtil.encryptPhone;
 
 /**
  * 用户Service业务层处理
@@ -468,6 +471,10 @@ public class FsUserServiceImpl implements IFsUserService
             //写入
             user=new FsUser();
             user.setPhone(param.getPhone());
+            Pattern PHONE_PATTERN = Pattern.compile("^1\\d{10}$");
+            if (PHONE_PATTERN.matcher(param.getPhone().trim()).matches()){
+                user.setPhone(encryptPhone(param.getPhone()));
+            }
             user.setNickname("微信用户");
             user.setStatus(1);
             user.setMaOpenId(param.getMaOpenId());
@@ -527,6 +534,11 @@ public class FsUserServiceImpl implements IFsUserService
         //写入
         user=new FsUser();
         user.setPhone(phoneNoInfo.getPhoneNumber());
+        //先看手机是否是11位,再加密查询
+        Pattern PHONE_PATTERN = Pattern.compile("^1\\d{10}$");
+        if (PHONE_PATTERN.matcher(phoneNoInfo.getPhoneNumber().trim()).matches()){
+            user.setPhone(encryptPhone(phoneNoInfo.getPhoneNumber()));
+        }
         user.setNickname("微信用户");
         user.setStatus(1);
         user.setMaOpenId(session.getOpenid());
@@ -551,6 +563,11 @@ public class FsUserServiceImpl implements IFsUserService
         }
         if(StringUtils.isNotEmpty(user.getPhone())){
             userMap.setPhone(user.getPhone());
+            Pattern PHONE_PATTERN = Pattern.compile("^1\\d{10}$");
+            if (PHONE_PATTERN.matcher(user.getPhone().trim()).matches()){
+                userMap.setPhone(encryptPhone(user.getPhone()));
+                logger.info("用户修改手机加密:" + userMap.getPhone());
+            }
         }
         if(StringUtils.isNotBlank(session.getOpenid())) {
             userMap.setMaOpenId(session.getOpenid());

+ 294 - 0
fs-service-system/src/main/java/com/fs/until/PhoneUtil.java

@@ -0,0 +1,294 @@
+package com.fs.until;
+
+import cn.hutool.http.HttpException;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.fs.common.core.domain.AjaxResult;
+import com.fs.common.utils.ParseUtils;
+import com.fs.common.utils.StringUtils;
+import com.fs.system.domain.SysConfig;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import javax.crypto.Cipher;
+import javax.crypto.spec.SecretKeySpec;
+import java.util.Base64;
+
+import static com.fs.common.core.domain.AjaxResult.CODE_TAG;
+import static com.fs.common.core.domain.AjaxResult.DATA_TAG;
+
+@Slf4j
+@Component
+public class PhoneUtil {
+
+    /**
+     * 2025-9-3 需求替换新 key
+     */
+    private static String OLD_KEY = "2c8d1a7f4e9b3c6ae6d5c4b3a291f8c9";
+
+    private static String USE_KEY = "AESAabCdeREssREA";
+
+
+    //外部刷新方法
+    public static void refreshKeyExternal(SysConfig config) {
+        String configValue = config.getConfigValue();
+        if (null != configValue) {
+            JSONObject jsonObject = JSON.parseObject(configValue);
+            if (jsonObject.containsKey("useKey") && jsonObject.containsKey("oldKey")) {
+                USE_KEY = jsonObject.getString("useKey");
+                OLD_KEY = jsonObject.getString("oldKey");
+            }
+        }
+    }
+
+    /**
+     * 加密
+     */
+    public static String encryptPhone(String text) {
+
+        try {
+            String encryptedText = null;
+            String url = "http://42.194.147.226:8000/app/common/genEncryption";
+            // 构建请求体 JSON
+            JSONObject jsonBody = new JSONObject();
+            jsonBody.put("content", text);
+
+            String result = HttpRequest.post(url).body(jsonBody.toString()).execute().body();
+            //解析返回
+            AjaxResult ajaxResult = JSONUtil.toBean(result, AjaxResult.class);
+
+            //取值返回参数
+            Object codeValue = ajaxResult.get(CODE_TAG);
+            Object dataValue = ajaxResult.get(DATA_TAG);
+
+            //判断是否成功
+            if ("200".equals(String.valueOf(codeValue))) {
+                encryptedText = String.valueOf(dataValue);
+            } else {
+                log.error("请求失败,状态码: " + codeValue);
+                return "";
+            }
+            return encryptedText;
+        } catch (HttpException e) {
+            throw new RuntimeException(e);
+        }
+
+    }
+
+
+    /**
+     * 解密
+     */
+    public static String decryptPhone(String encryptedText) {
+
+        try {
+            String text = null;
+            String url = "http://42.194.147.226:8000/app/common/genDecryption";
+            // 构建请求体 JSON
+            JSONObject jsonBody = new JSONObject();
+            jsonBody.put("content", encryptedText);
+
+            String result = HttpRequest.post(url).body(jsonBody.toString()).execute().body();
+            //解析返回
+            AjaxResult ajaxResult = JSONUtil.toBean(result, AjaxResult.class);
+
+            //取值返回参数
+            Object codeValue = ajaxResult.get(CODE_TAG);
+            Object dataValue = ajaxResult.get(DATA_TAG);
+
+            //判断是否成功
+            if ("200".equals(String.valueOf(codeValue))) {
+                text = String.valueOf(dataValue);
+            } else {
+                log.error("请求失败,状态码: " + codeValue);
+                return "";
+            }
+            return text;
+        } catch (HttpException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+
+    /**
+     * 用于查询 使用老的数据加密
+     *
+     * @param text
+     * @return
+     */
+    public static String encryptPhoneOldKey(String text) {
+        String encryptedText = null;
+        try {
+            SecretKeySpec secretKey = new SecretKeySpec(OLD_KEY.getBytes(), "AES");
+            Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
+            // Encryption
+            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
+            byte[] encryptedBytes = cipher.doFinal(text.getBytes());
+            encryptedText = Base64.getEncoder().encodeToString(encryptedBytes);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return encryptedText;
+    }
+
+    //
+    public static void main(String[] args) {
+
+        String text = null;
+        String url = "http://172.16.0.114:8000/app/common/genEncryption";
+        // 构建请求体 JSON
+        JSONObject jsonBody = new JSONObject();
+        jsonBody.put("content", "17749925835");
+
+        String result = HttpRequest.post(url)
+                .body(jsonBody.toString())
+                .execute()
+                .body();
+        AjaxResult ajaxResult = JSONUtil.toBean(result, AjaxResult.class);
+        System.out.println("完整响应: " + ajaxResult);
+
+        Object codeValue = ajaxResult.get(CODE_TAG);
+        Object dataValue = ajaxResult.get(DATA_TAG);
+
+        System.out.println("code原始值: '" + codeValue + "'");
+        System.out.println("data原始值: '" + dataValue + "'");
+
+        // 使用 String.valueOf 确保类型安全
+        if ("200".equals(String.valueOf(codeValue))) {
+            text = String.valueOf(dataValue);
+            System.out.println("加密结果: " + text);
+        } else {
+            System.out.println("请求失败,状态码: " + codeValue);
+        }
+    }
+
+
+    /**
+     * 解密加*
+     */
+    public static String decryptPhoneMk(String encryptedText) {
+        String text = null;
+        try {
+            text = decryptPhone(encryptedText);
+            text = text.replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2");
+        } catch (Exception e) {
+            log.warn("decryptPhoneMk 解密失败 text: {}, msg: {}", encryptedText, e.getMessage(), e);
+            text = encryptedText;
+        }
+        return text;
+    }
+
+    public static String decryptAutoPhoneMk(String encryptedText) {
+        String text = null;
+        if (encryptedText != null && encryptedText != "") {
+            if (encryptedText.length() > 11) {
+                try {
+                    text = decryptPhone(encryptedText);
+                    text = text.replaceAll("(\\d{3})\\d*(\\d{4})", "$1****$2");
+                } catch (Exception e) {
+                    log.warn("decryptAutoPhoneMk 解密失败 text: {}, msg: {}", encryptedText, e.getMessage(), e);
+                    text = encryptedText;
+                }
+            } else {
+                text = ParseUtils.parsePhone(encryptedText);
+            }
+        }
+
+        return text;
+    }
+
+    /**
+     * 手机号加密 *
+     *
+     * @param text 手机号
+     * @return 加密后手机号
+     */
+    public static String hiddenPhone(String text) {
+        if (StringUtils.isBlank(text)) {
+            return text;
+        }
+
+        return "***********";
+    }
+
+    /**
+     * 显示前3位
+     *
+     * @param text 手机号
+     * @return 加密后手机号
+     */
+    public static String displayPre3Phone(String text) {
+        if (StringUtils.isBlank(text)) {
+            return text;
+        }
+
+        text = text.trim();
+        if (text.length() > 11) {
+            text = decryptPhone(text);
+        }
+
+        return text.replaceAll("(\\d{3})\\d*", "$1********");
+    }
+
+
+    /**
+     * 判断文本中是否存在手机号
+     *
+     * @param text 原始文本
+     * @return 是否存在手机号
+     */
+    private static boolean containsPhoneNumber(String text) {
+        if (text == null || text.trim().isEmpty()) {
+            return false;
+        }
+
+        // 手机号正则
+        String phoneRegex = "1[3-9]\\d{9}";
+        java.util.regex.Pattern pattern = java.util.regex.Pattern.compile(phoneRegex);
+        java.util.regex.Matcher matcher = pattern.matcher(text);
+
+        return matcher.find();
+    }
+
+    private static final String PUBLIC_KEY_STR = "ylrz112233";
+
+    /**
+     * XOR 加密(返回 Base64)(对于解析后的电话明文加密,适用于前端解密)
+     *
+     * @param data 明文电话
+     * @return String 密文
+     */
+    public static String xorEncrypt(String data) {
+        byte[] dataBytes = data.getBytes(java.nio.charset.StandardCharsets.UTF_8);
+        byte[] keyBytes = PUBLIC_KEY_STR.getBytes(java.nio.charset.StandardCharsets.UTF_8);
+        byte[] result = new byte[dataBytes.length];
+        for (int i = 0; i < dataBytes.length; i++) {
+            result[i] = (byte) (dataBytes[i] ^ keyBytes[i % keyBytes.length]);
+        }
+        return Base64.getEncoder().encodeToString(result);
+    }
+
+
+    /**
+     * XOR 解密
+     *
+     * @param base64Str  Base64 编码的密文
+     * @param privateKey 私钥字符串(如 "ylrz987654321")
+     * @return 解密后的明文字符串
+     */
+    public static String xorDecrypt(String base64Str, String privateKey) {
+        // 1. Base64 解码为字节数组
+        byte[] encryptedBytes = Base64.getDecoder().decode(base64Str);
+        // 2. 私钥字符串转字节数组(UTF-8 编码)
+        byte[] keyBytes = privateKey.getBytes(java.nio.charset.StandardCharsets.UTF_8);
+        // 3. 逐字节异或
+        byte[] resultBytes = new byte[encryptedBytes.length];
+        for (int i = 0; i < encryptedBytes.length; i++) {
+            resultBytes[i] = (byte) (encryptedBytes[i] ^ keyBytes[i % keyBytes.length]);
+        }
+        // 4. 将字节数组按 UTF-8 解码为字符串
+        return new String(resultBytes, java.nio.charset.StandardCharsets.UTF_8);
+    }
+}

+ 21 - 2
fs-user-app/src/main/java/com/fs/app/controller/WxUserController.java

@@ -35,6 +35,9 @@ import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.regex.Pattern;
+
+import static com.fs.until.PhoneUtil.encryptPhone;
 
 /**
  * 微信小程序用户接口
@@ -72,6 +75,7 @@ public class WxUserController extends AppBaseController{
     @ApiOperation("登录")
     @PostMapping("/login")
     public R login( @RequestBody LoginMpWxParam param) {
+        Pattern PHONE_PATTERN = Pattern.compile("^1\\d{10}$");
         if (StringUtils.isBlank(param.getCode())) {
             return R.error("code不存在");
         }
@@ -85,8 +89,13 @@ public class WxUserController extends AppBaseController{
             FsUser user=userService.selectFsUserByMaOpenId(session.getOpenid());
             String ip = IpUtil.getRequestIp();
             if(user==null){
-                //查询手机号是否存在,如果存在,更新
-                FsUser checkPhone=userService.selectFsUserByPhone(phoneNoInfo.getPhoneNumber());
+                FsUser checkPhone = null;
+                //先看手机是否是11位,再加密查询
+                if (PHONE_PATTERN.matcher(phoneNoInfo.getPhoneNumber().trim()).matches()){
+                    String phone = encryptPhone(phoneNoInfo.getPhoneNumber());
+                    logger.info("登录,用户为空,电话明文:" + phoneNoInfo.getPhoneNumber() + "电话密文:" + phone);
+                    checkPhone = userService.selectFsUserByPhone(phone);
+                }
                 if(checkPhone!=null){
                     if(checkPhone.getMaOpenId()==null){
                         user=checkPhone;
@@ -115,6 +124,11 @@ public class WxUserController extends AppBaseController{
                     user.setUserCode(OrderUtils.genUserCode());
                     user.setPhone(phoneNoInfo.getPhoneNumber());
                     user.setUsername(phoneNoInfo.getPhoneNumber());
+                    logger.info("登录:手机存在电话明文:" + phoneNoInfo.getPhoneNumber());
+                    if (PHONE_PATTERN.matcher(phoneNoInfo.getPhoneNumber().trim()).matches()){
+                        user.setPhone(encryptPhone(phoneNoInfo.getPhoneNumber()));
+                        logger.info("登录:手机存在电话密文:" + user.getPhone());
+                    }
                     user.setNickname("微信用户");
                     user.setStatus(1);
                     user.setMaOpenId(session.getOpenid());
@@ -127,6 +141,11 @@ public class WxUserController extends AppBaseController{
            else{
                FsUser userMap=new FsUser();
                userMap.setPhone(phoneNoInfo.getPhoneNumber());
+                logger.info("用户存在,电话明文:" + phoneNoInfo.getPhoneNumber());
+                if (PHONE_PATTERN.matcher(phoneNoInfo.getPhoneNumber().trim()).matches()){
+                    userMap.setPhone(encryptPhone(phoneNoInfo.getPhoneNumber()));
+                    logger.info("用户存在,电话密文::" + userMap.getPhone());
+                }
                userMap.setUserId(user.getUserId());
                userMap.setUpdateTime(new DateTime());
                userMap.setLastIp(ip);