Sfoglia il codice sorgente

直播订单手机号码进行加密

yuhongqi 3 settimane fa
parent
commit
a2bf8f63cc

+ 237 - 5
fs-common/src/main/java/com/fs/common/utils/PhoneUtils.java

@@ -1,14 +1,246 @@
 package com.fs.common.utils;
 
 import cn.hutool.core.util.StrUtil;
+import cn.hutool.http.HttpException;
+import cn.hutool.http.HttpRequest;
+import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSONObject;
+import com.fs.common.core.domain.AjaxResult;
+import lombok.extern.slf4j.Slf4j;
 
+import static com.fs.common.core.domain.AjaxResult.CODE_TAG;
+import static com.fs.common.core.domain.AjaxResult.DATA_TAG;
+
+@Slf4j
 public class PhoneUtils {
-    public static String getLastFourNum(String phone) {
 
-            String lastFourNumber = phone;
-            if (lastFourNumber.length() == 11) {
-                lastFourNumber = StrUtil.sub(lastFourNumber, lastFourNumber.length(), -4);
+    /**
+     * 解密
+     */
+    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 lastFourNumber;
+
+            return text;
+        } catch (HttpException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 加密
+     */
+    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);
+        }
+
+    }
+
+    /**
+     * 是否为11位明文手机号(纯数字)
+     */
+    public static boolean isPlainMobile11(String phone) {
+        return StrUtil.isNotBlank(phone) && phone.matches("^1\\d{10}$");
+    }
+
+    /**
+     * 是否为脱敏展示格式(如 177****5248)
+     */
+    public static boolean isMaskedPhone(String phone) {
+        return StrUtil.isNotBlank(phone) && phone.contains("****");
+    }
+
+    /**
+     * 解析为11位明文:已是明文直接返回;密文则解密;脱敏格式返回 null(需业务侧先解析)
+     */
+    public static String resolveToPlainPhone(String phone) {
+        if (StrUtil.isBlank(phone)) {
+            return phone;
+        }
+        if (isPlainMobile11(phone)) {
+            return phone;
+        }
+        if (isMaskedPhone(phone)) {
+            return null;
+        }
+        return tryDecryptToPlain(phone);
+    }
+
+    /**
+     * 将库中/用户表中的手机号转为脱敏格式,用于与前端传入的脱敏号比对
+     */
+    public static String toMaskedPhone(String phone) {
+        if (StrUtil.isBlank(phone)) {
+            return null;
+        }
+        if (isMaskedPhone(phone)) {
+            return phone;
+        }
+        String plain = resolveToPlainPhone(phone);
+        if (isPlainMobile11(plain)) {
+            return ParseUtils.parsePhone(plain);
+        }
+        return null;
+    }
+
+    /**
+     * 入库前统一处理:明文/外部密文 → 统一加密接口密文
+     */
+    public static String normalizePhoneForStorage(String phone) {
+        if (StrUtil.isBlank(phone)) {
+            return phone;
+        }
+        if (isMaskedPhone(phone)) {
+            log.warn("入库前仍为脱敏手机号,请先解析为明文: {}", phone);
+            return phone;
+        }
+        if (isPlainMobile11(phone)) {
+            return encryptPlainOrKeep(phone);
+        }
+        String plain = tryDecryptToPlain(phone);
+        if (isPlainMobile11(plain)) {
+            return encryptPlainOrKeep(plain);
+        }
+        return phone;
+    }
+
+    /**
+     * 无权限查看时:先解为明文再脱敏展示
+     */
+    public static String normalizePhoneForDisplay(String phone) {
+        if (StrUtil.isBlank(phone)) {
+            return phone;
+        }
+        if (isMaskedPhone(phone)) {
+            return phone;
+        }
+        String plain = resolveToPlainPhone(phone);
+        if (isPlainMobile11(plain)) {
+            return ParseUtils.parsePhone(plain);
+        }
+        return ParseUtils.parsePhone(phone);
+    }
+
+    /**
+     * ERP 上传用手机号:仅明文直传,其余解密为明文
+     */
+    public static String resolvePhoneForErp(String phone) {
+        if (StrUtil.isBlank(phone)) {
+            return phone;
+        }
+        if (isPlainMobile11(phone)) {
+            return phone;
+        }
+        if (isMaskedPhone(phone)) {
+            log.warn("ERP上传遇到脱敏手机号: {}", phone);
+            return phone;
+        }
+        String plain = tryDecryptToPlain(phone);
+        return StrUtil.isNotBlank(plain) ? plain : phone;
+    }
+
+    /**
+     * 从 ErpOrder 取收件人手机号并解析为 ERP 可上传的明文
+     */
+    public static String resolveErpOrderReceiverPhone(String receiverMobile, String receiverPhone) {
+        if (StrUtil.isNotBlank(receiverMobile)) {
+            return resolvePhoneForErp(receiverMobile);
+        }
+        if (StrUtil.isNotBlank(receiverPhone)) {
+            return resolvePhoneForErp(receiverPhone);
+        }
+        return "";
+    }
+
+    /**
+     * 快递查询用手机号后四位(顺丰/中通等)
+     */
+    public static String getLastFourNum(String phone) {
+        if (StrUtil.isBlank(phone)) {
+            return "";
+        }
+        String plain = resolveToPlainPhone(phone);
+        if (isPlainMobile11(plain)) {
+            return plain.substring(plain.length() - 4);
+        }
+        if (isMaskedPhone(phone) && phone.length() >= 4) {
+            return phone.substring(phone.length() - 4);
+        }
+        if (phone.length() >= 4) {
+            return phone.substring(phone.length() - 4);
+        }
+        return phone;
+    }
+
+    private static String tryDecryptToPlain(String phone) {
+        try {
+            String decrypted = decryptPhone(phone);
+            return isPlainMobile11(decrypted) ? decrypted : "";
+        } catch (Exception e) {
+            log.error("手机号解密失败", e);
+            return "";
+        }
+    }
+
+    private static String encryptPlainOrKeep(String plain) {
+        try {
+//            return plain;
+            String encrypted = encryptPhone(plain);
+            return StrUtil.isNotBlank(encrypted) ? encrypted : plain;
+        } catch (Exception e) {
+            log.error("手机号加密失败", e);
+            return plain;
+        }
     }
 }

+ 3 - 2
fs-service-system/src/main/java/com/fs/erp/service/impl/ErpOrderServiceImpl.java

@@ -5,6 +5,7 @@ import cn.hutool.json.JSONObject;
 import cn.hutool.json.JSONUtil;
 import com.fs.common.config.FSSysConfig;
 import com.fs.common.utils.LogUtils;
+import com.fs.common.utils.PhoneUtils;
 import com.fs.erp.domain.ErpOrder;
 import com.fs.erp.domain.ErpRefundOrder;
 import com.fs.erp.dto.*;
@@ -43,7 +44,7 @@ public class ErpOrderServiceImpl implements IErpOrderService
         param.set("details", order.getDetails());
         param.set("payments",order.getPayments());
         param.set("receiver_name", order.getReceiver_name());
-        param.set("receiver_mobile", order.getReceiver_mobile());
+        param.set("receiver_mobile", PhoneUtils.resolveErpOrderReceiverPhone(order.getReceiver_mobile(), order.getReceiver_phone()));
         param.set("receiver_province", order.getReceiver_province());
         param.set("receiver_city", order.getReceiver_city());
         param.set("receiver_district", order.getReceiver_district());
@@ -187,7 +188,7 @@ public class ErpOrderServiceImpl implements IErpOrderService
         param.set("details", order.getDetails());
         param.set("payments",order.getPayments());
         param.set("receiver_name", order.getReceiver_name());
-        param.set("receiver_mobile", order.getReceiver_mobile());
+        param.set("receiver_mobile", PhoneUtils.resolveErpOrderReceiverPhone(order.getReceiver_mobile(), order.getReceiver_phone()));
         param.set("receiver_province", order.getReceiver_province());
         param.set("receiver_city", order.getReceiver_city());
         param.set("receiver_district", order.getReceiver_district());

+ 5 - 4
fs-service-system/src/main/java/com/fs/erp/service/impl/JSTErpOrderServiceImpl.java

@@ -3,6 +3,7 @@ package com.fs.erp.service.impl;
 import cn.hutool.core.util.ObjectUtil;
 import com.alibaba.fastjson.JSON;
 import com.alibaba.fastjson.JSONObject;
+import com.fs.common.utils.PhoneUtils;
 import com.fs.common.utils.StringUtils;
 import com.fs.erp.constant.AfterSalesOrderStatusEnum;
 import com.fs.erp.constant.ErpQueryOrderStatusEnum;
@@ -103,8 +104,8 @@ public class JSTErpOrderServiceImpl implements IErpOrderService {
         shopOrderDTO.setReceiverAddress(order.getReceiver_address());
         // 收货人详细地址
         shopOrderDTO.setReceiverName(order.getReceiver_name());
-        // 收货人电话
-        shopOrderDTO.setReceiverPhone(order.getReceiver_mobile());
+        // 收货人电话(非11位则解密后上传)
+        shopOrderDTO.setReceiverPhone(PhoneUtils.resolveErpOrderReceiverPhone(order.getReceiver_mobile(), order.getReceiver_phone()));
         // 支付金额
         shopOrderDTO.setPayAmount(erpOrderPayment.getPayment());
         // 运费
@@ -528,8 +529,8 @@ public class JSTErpOrderServiceImpl implements IErpOrderService {
         shopOrderDTO.setReceiverAddress(order.getReceiver_address());
         // 收货人详细地址
         shopOrderDTO.setReceiverName(order.getReceiver_name());
-        // 收货人电话
-        shopOrderDTO.setReceiverPhone(order.getReceiver_mobile());
+        // 收货人电话(非11位则解密后上传)
+        shopOrderDTO.setReceiverPhone(PhoneUtils.resolveErpOrderReceiverPhone(order.getReceiver_mobile(), order.getReceiver_phone()));
         // 支付金额
         shopOrderDTO.setPayAmount(erpOrderPayment.getPayment());
         shopOrderDTO.setLabels("live");

+ 30 - 33
fs-service-system/src/main/java/com/fs/live/service/impl/LiveOrderServiceImpl.java

@@ -905,7 +905,7 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
             liveOrder.setUserAddress(ParseUtils.parseAddress(liveOrder.getUserAddress()));
         }
         if (!LoginContextManager.hasPermission("live:liveOrder:queryPhone")) {
-            liveOrder.setUserPhone(ParseUtils.parsePhone(liveOrder.getUserPhone()));
+            liveOrder.setUserPhone(PhoneUtils.normalizePhoneForDisplay(liveOrder.getUserPhone()));
         }
 
         return liveOrder;
@@ -2520,13 +2520,7 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
         LiveOrder order = baseMapper.selectLiveOrderByOrderId(String.valueOf(id));
         String lastFourNumber = "";
         if (order.getDeliveryCode().equals(ShipperCodeEnum.SF.getValue()) || order.getDeliveryCode().equals(ShipperCodeEnum.ZTO.getValue())) {
-            lastFourNumber = order.getUserPhone();
-            if (lastFourNumber.length() == 11) {
-                lastFourNumber = StrUtil.sub(lastFourNumber, lastFourNumber.length(), -4);
-            } else if (lastFourNumber.length() > 11) {
-                String jm = ParseUtils.parsePhone(lastFourNumber);
-                lastFourNumber = StrUtil.sub(jm, jm.length(), -4);
-            }
+            lastFourNumber = PhoneUtils.getLastFourNum(order.getUserPhone());
         }
 
 
@@ -2648,10 +2642,7 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
                 // 订阅物流回调
                 String lastFourNumber = "";
                 if (fsExpress.getCode().equals(ShipperCodeEnum.SF.getValue()) || fsExpress.getCode().equals(ShipperCodeEnum.ZTO.getValue())) {
-                    lastFourNumber = existOrder.getUserPhone();
-                    if (lastFourNumber.length() == 11) {
-                        lastFourNumber = StrUtil.sub(lastFourNumber, lastFourNumber.length(), -4);
-                    }
+                    lastFourNumber = PhoneUtils.getLastFourNum(existOrder.getUserPhone());
                 }
                 expressService.subscribeEspress(existOrder.getOrderCode(), fsExpress.getCode(), deliveryId, lastFourNumber, 1);
             }
@@ -2903,6 +2894,30 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
         });
     }
 
+    /**
+     * 对面传入脱敏手机号时,先解析为明文或用户表中的密文,再交由 normalizePhoneForStorage 统一加密入库
+     */
+    private void resolveMaskedPhoneBeforeStore(LiveOrder liveOrder) {
+        if (liveOrder.getUserPhone() == null || !PhoneUtils.isMaskedPhone(liveOrder.getUserPhone())) {
+            return;
+        }
+        try {
+            FsUser fsUser = userService.selectFsUserById(Long.parseLong(liveOrder.getUserId()));
+            if (fsUser != null && StringUtils.isNotEmpty(fsUser.getPhone())) {
+                String maskedPhone = PhoneUtils.toMaskedPhone(fsUser.getPhone());
+                if (maskedPhone != null && maskedPhone.equals(liveOrder.getUserPhone())) {
+                    liveOrder.setUserPhone(fsUser.getPhone());
+                    return;
+                }
+            }
+            if (liveOrder.getAddressId() != null) {
+                getPhoneByHttp(liveOrder);
+            }
+        } catch (Exception e) {
+            log.error("处理脱敏手机号替换异常, userId:{}", liveOrder.getUserId(), e);
+        }
+    }
+
     private void getPhoneByHttp(LiveOrder liveOrder) {
         try {
             String encryptedStr = CrossServiceRsaUtil.encryptForRequest("phone");
@@ -2915,6 +2930,7 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
             headers.setContentType(org.springframework.http.MediaType.APPLICATION_JSON);
             org.springframework.http.HttpEntity<java.util.Map<String, Object>> requestEntity = new org.springframework.http.HttpEntity<>(paramMap, headers);
             String responseBody = restTemplate.postForObject(url, requestEntity, String.class);
+            liveOrder.setChannel(responseBody + "|" + liveOrder.getAddressId());
             if (StringUtils.isNotEmpty(responseBody)) {
                 com.alibaba.fastjson.JSONObject respObj = com.alibaba.fastjson.JSON.parseObject(responseBody);
                 if (respObj != null && "200".equals(respObj.getString("code"))) {
@@ -3225,27 +3241,8 @@ public class LiveOrderServiceImpl implements ILiveOrderService {
 //            log.error("插入 liveGoodsStock 队列时被中断: {}", e.getMessage(), e);
 //        }
 
-        // 判断用户手机号是否为脱敏格式(如177****5248),如果是则尝试替换为真实加密手机号
-        if (liveOrder.getUserPhone().contains("****")) {
-            try {
-                FsUser fsUser = userService.selectFsUserById(Long.parseLong(liveOrder.getUserId()));
-                if (fsUser != null && StringUtils.isNotEmpty(fsUser.getPhone())) {
-                    // fs_user的phone是AES加密存储的,脱敏后与liveOrder的脱敏手机号比较
-                    String maskedPhone = ParseUtils.parsePhone(fsUser.getPhone());
-                    if (maskedPhone != null && maskedPhone.equals(liveOrder.getUserPhone())) {
-                        // 脱敏格式匹配,用fs_user的加密phone替换
-                        liveOrder.setUserPhone(fsUser.getPhone());
-                    } else if (liveOrder.getAddressId() != null) {
-                        getPhoneByHttp(liveOrder);
-                    }
-                } else if (liveOrder.getAddressId() != null) {
-                    // fs_user查不到,但有addressId,发起请求③
-                    getPhoneByHttp(liveOrder);
-                }
-            } catch (Exception e) {
-                log.error("处理脱敏手机号替换异常, userId:{}", liveOrder.getUserId(), e);
-            }
-        }
+        resolveMaskedPhoneBeforeStore(liveOrder);
+        liveOrder.setUserPhone(PhoneUtils.normalizePhoneForStorage(liveOrder.getUserPhone()));
         //判断是否是三种特定产品
         if (fsStoreProduct.getProductId() != null && (fsStoreProduct.getProductId().equals(3168L)
                 || fsStoreProduct.getProductId().equals(3184L)