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); }