刘帅
2026-09-20 a3bfafde009c644c21ee8c9971b436f4cd7481f1
feat:手机号隐私问题
5个文件已修改
57 ■■■■■ 已修改文件
cloud-server-account/src/main/java/com/dsh/account/controller/AppUserController.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-account/src/main/java/com/dsh/account/model/vo/userBenefitDetail/AppUserDetailsVo.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-gateway/src/main/java/cn/mb/cloud/gateway/filter/SensitiveDataMaskingGlobalFilter.java 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-other/src/main/java/com/dsh/other/controller/SiteController.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-other/src/main/java/com/dsh/other/feignclient/account/AppUserClient.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
cloud-server-account/src/main/java/com/dsh/account/controller/AppUserController.java
@@ -269,6 +269,24 @@
    }
    /**
     * Internal data source used when an APP booking submits its displayed,
     * masked phone number.  Limit the response to the single field needed for
     * that booking; callers must use the internal sensitive-data header.
     */
    @PostMapping("/internal/sensitive/site-booking/app-user/{id}/phone")
    public Map<String, Object> siteBookingPhone(@PathVariable("id") Integer id,
                                                @RequestHeader(value = "X-Internal-Sensitive-Access", required = false) String access) {
        if (!"true".equalsIgnoreCase(access)) {
            throw new IllegalStateException("Sensitive data access is restricted to site booking");
        }
        TAppUser user = appUserService.getById(id);
        if (user == null) return null;
        Map<String, Object> result = new java.util.HashMap<String, Object>();
        result.put("phone", user.getPhone());
        return result;
    }
    /**
     * 冻结/解冻 1=解冻 2=冻结
     */
    @RequestMapping("/base/appUser/changeState")
cloud-server-account/src/main/java/com/dsh/account/model/vo/userBenefitDetail/AppUserDetailsVo.java
@@ -1,7 +1,6 @@
package com.dsh.account.model.vo.userBenefitDetail;
import com.dsh.privacy.UnmaskedSensitiveData;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -17,7 +16,6 @@
    private String userName;
    @ApiModelProperty(value = "用户手机号")
    @UnmaskedSensitiveData
    private String userPhone;
    @ApiModelProperty(value = "用户性别")
cloud-server-gateway/src/main/java/cn/mb/cloud/gateway/filter/SensitiveDataMaskingGlobalFilter.java
@@ -21,13 +21,6 @@
/** Final API boundary for APP traffic, including responses returned by every service. */
@Component
public class SensitiveDataMaskingGlobalFilter implements GlobalFilter, Ordered {
    /**
     * This response contains the current user's own phone number, which the APP
     * needs in its original form.  The account service marks the field with
     * {@code @UnmaskedSensitiveData}; the gateway works on JSON text, so it
     * must mirror that narrow exception here.
     */
    private static final String UNMASKED_USER_DETAILS_PATH = "/account/api/useBenefit/userDetails";
    private static final Pattern FIELD = Pattern.compile("(?i)(\\\"(?:[a-z]*phone|[a-z]*mobile|telephone|tel)\\\"\\s*:\\s*\\\")([^\\\"]*)(\\\")");
    private static final Pattern IDCARD = Pattern.compile("(?i)(\\\"(?:[a-z]*idcard|[a-z]*identitycard|identitynumber|idnumber)\\\"\\s*:\\s*\\\")([^\\\"]*)(\\\")");
@@ -35,8 +28,7 @@
    @Override public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        // This route itself enforces the admin check and writes an audit record.
        String path = exchange.getRequest().getURI().getPath();
        if (path.startsWith("/system/sensitive/") || UNMASKED_USER_DETAILS_PATH.equals(path)) return chain.filter(exchange);
        if (exchange.getRequest().getURI().getPath().startsWith("/system/sensitive/")) return chain.filter(exchange);
        ServerHttpResponseDecorator decorated = new ServerHttpResponseDecorator(exchange.getResponse()) {
            @Override public Mono<Void> writeWith(Publisher<? extends DataBuffer> body) {
                MediaType type = getHeaders().getContentType();
cloud-server-other/src/main/java/com/dsh/other/controller/SiteController.java
@@ -14,6 +14,7 @@
import com.dsh.other.enums.SiteBookingStatusEnum;
import com.dsh.other.mapper.QrLinkMapper;
import com.dsh.other.feignclient.CourseRecordClient;
import com.dsh.other.feignclient.account.AppUserClient;
import com.dsh.other.feignclient.account.CityManagerClient;
import com.dsh.other.feignclient.activity.UserCouponClient;
import com.dsh.other.feignclient.activity.model.QueryUserCouponByIdAndUserId;
@@ -53,6 +54,7 @@
import java.util.*;
import java.security.SecureRandom;
import java.util.stream.Collectors;
import java.util.regex.Pattern;
/**
 * @author zhibing.pu
@@ -64,6 +66,7 @@
public class SiteController {
    private static final char[] ENTRY_CODE_CHARS = "23456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray();
    private static final Pattern MAINLAND_MOBILE = Pattern.compile("^1[3-9]\\d{9}$");
    private final SecureRandom entryCodeRandom = new SecureRandom();
    @Autowired
@@ -89,6 +92,8 @@
    @Resource
    private CityManagerClient cityManagerClient;
    @Resource
    private AppUserClient appUserClient;
    @Autowired
    private IOperatorUserService operatorUserService;
@@ -390,6 +395,19 @@
            if (null == uid) {
                return ResultUtil.tokenErr();
            }
            String phone = reservationSite.getPhone();
            if (phone != null && phone.contains("*")) {
                Map<String, Object> userPhone = appUserClient.siteBookingPhone(uid, "true");
                Object originalPhone = userPhone == null ? null : userPhone.get("phone");
                if (!(originalPhone instanceof String) || ((String) originalPhone).trim().isEmpty()) {
                    return ResultUtil.error("未获取到用户原始手机号");
                }
                reservationSite.setPhone((String) originalPhone);
            } else if (phone == null || !MAINLAND_MOBILE.matcher(phone.trim()).matches()) {
                return ResultUtil.error("请输入正确的手机号");
            } else {
                reservationSite.setPhone(phone.trim());
            }
//            Integer uid = 201;
            return siteService.reservationSite(uid, reservationSite);
        } catch (Exception e) {
cloud-server-other/src/main/java/com/dsh/other/feignclient/account/AppUserClient.java
@@ -2,7 +2,11 @@
import com.dsh.other.feignclient.account.model.AppUser;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import java.util.Map;
/**
 * @author zhibing.pu
@@ -28,4 +32,9 @@
     */
    @PostMapping("/base/appUser/updateAppUser")
    void updateAppUser(AppUser appUser);
    /** Gets only the original phone for the authenticated user's site booking. */
    @PostMapping("/internal/sensitive/site-booking/app-user/{id}/phone")
    Map<String, Object> siteBookingPhone(@PathVariable("id") Integer appUserId,
                                         @RequestHeader("X-Internal-Sensitive-Access") String sensitiveAccess);
}