From 68fb2b9cf9385448f007047a9a48d16eb3930197 Mon Sep 17 00:00:00 2001 From: DaxPay Dev Date: Mon, 20 Jul 2026 15:50:56 +0800 Subject: [PATCH] =?UTF-8?q?feat(risk):=20=E5=A2=9E=E5=8A=A0=E6=8B=A6?= =?UTF-8?q?=E6=88=AA=E7=BA=A7=E5=88=AB=E5=BC=80=E5=85=B3=E4=B8=8E=E6=B5=B7?= =?UTF-8?q?=E5=A4=96IP=E6=8B=A6=E6=88=AA=E5=8D=A0=E4=BD=8D=E5=AD=97?= =?UTF-8?q?=E6=AE=B5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 PayRiskOpenIdLevelEnum 枚举(NORMAL/ENHANCED), 控制对 H5/主扫等免 openId 方式是否强制 OAuth - PlatformPaySecurityConfig 增加 riskOpenIdLevel 与 blockOverseasIp 字段(后者占位, 后续接入 IP 地理位置库) - AggregatePayService/CashierPayService/CodePayAssistService 在 hasOpenIdBlacklist 调用前先判 level=NORMAL 短路 - 同步 10 语种 validation 与新增 enum/pay_risk_open_id_level.json --- .../pay/gateway/AggregatePayService.java | 15 ++++++-- .../pay/gateway/CashierPayService.java | 15 ++++++-- .../client/service/CodePayAssistService.java | 15 ++++++-- .../en-US/enum/pay_risk_open_id_level.json | 4 +++ .../main/resources/i18n/en-US/validation.json | 6 ++++ .../id-ID/enum/pay_risk_open_id_level.json | 4 +++ .../main/resources/i18n/id-ID/validation.json | 6 ++++ .../ja-JP/enum/pay_risk_open_id_level.json | 4 +++ .../main/resources/i18n/ja-JP/validation.json | 6 ++++ .../ko-KR/enum/pay_risk_open_id_level.json | 4 +++ .../main/resources/i18n/ko-KR/validation.json | 6 ++++ .../ms-MY/enum/pay_risk_open_id_level.json | 4 +++ .../main/resources/i18n/ms-MY/validation.json | 6 ++++ .../th-TH/enum/pay_risk_open_id_level.json | 4 +++ .../main/resources/i18n/th-TH/validation.json | 6 ++++ .../vi-VN/enum/pay_risk_open_id_level.json | 4 +++ .../main/resources/i18n/vi-VN/validation.json | 6 ++++ .../zh-CN/enum/pay_risk_open_id_level.json | 4 +++ .../main/resources/i18n/zh-CN/validation.json | 6 ++++ .../zh-HK/enum/pay_risk_open_id_level.json | 4 +++ .../main/resources/i18n/zh-HK/validation.json | 6 ++++ .../zh-TW/enum/pay_risk_open_id_level.json | 4 +++ .../main/resources/i18n/zh-TW/validation.json | 6 ++++ .../security/PlatformPaySecurityConfig.java | 10 ++++++ .../system/enums/PayRiskOpenIdLevelEnum.java | 36 +++++++++++++++++++ .../PlatformPaySecurityConfigParam.java | 8 +++++ .../PlatformPaySecurityConfigResult.java | 6 ++++ .../PlatformSecurityConfigService.java | 7 ++-- 28 files changed, 204 insertions(+), 8 deletions(-) create mode 100644 daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/en-US/enum/pay_risk_open_id_level.json create mode 100644 daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/id-ID/enum/pay_risk_open_id_level.json create mode 100644 daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ja-JP/enum/pay_risk_open_id_level.json create mode 100644 daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ko-KR/enum/pay_risk_open_id_level.json create mode 100644 daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ms-MY/enum/pay_risk_open_id_level.json create mode 100644 daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/th-TH/enum/pay_risk_open_id_level.json create mode 100644 daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/vi-VN/enum/pay_risk_open_id_level.json create mode 100644 daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-CN/enum/pay_risk_open_id_level.json create mode 100644 daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-HK/enum/pay_risk_open_id_level.json create mode 100644 daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-TW/enum/pay_risk_open_id_level.json create mode 100644 daxpay-platform/daxpay-platform-service/service-system/src/main/java/cn/daxpay/open/platform/system/enums/PayRiskOpenIdLevelEnum.java diff --git a/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/trade/runtime/service/pay/gateway/AggregatePayService.java b/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/trade/runtime/service/pay/gateway/AggregatePayService.java index 63cc2a01d..11332e9a1 100644 --- a/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/trade/runtime/service/pay/gateway/AggregatePayService.java +++ b/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/trade/runtime/service/pay/gateway/AggregatePayService.java @@ -15,6 +15,8 @@ import cn.daxpay.open.payment.unipay.result.trade.pay.NormalPayResult; import cn.daxpay.open.platform.common.spring.util.WebServletUtil; import cn.daxpay.open.platform.core.code.CommonErrorCode; import cn.daxpay.open.platform.core.exception.BizInfoException; +import cn.daxpay.open.platform.system.enums.PayRiskOpenIdLevelEnum; +import cn.daxpay.open.platform.system.service.config.security.PlatformSecurityConfigService; import cn.hutool.core.util.StrUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -37,6 +39,8 @@ public class AggregatePayService { private final GatewayAggregateConfigManager aggregateConfigManager; /// 风控检查器(可选 SPI:用于判断是否存在 openId 黑名单, 决定是否触发强制 OAuth) private final ObjectProvider payRiskCheckerProvider; + /// 平台安全配置(读取 openId 拦截级别, 决定 NORMAL 模式下不触发强制 OAuth) + private final PlatformSecurityConfigService platformSecurityConfigService; /// H5 聚合元数据: autoLaunch / needOpenId(不下发敏感路由字段) public AggregatePayMetaResult getMeta(String orderNo, String clientEnvCode, String runtimeCode) { @@ -79,16 +83,23 @@ public class AggregatePayService { /// openId 触发判定 /// /// 1. JSAPI/MINI 类方式: 业务必需, 永远 true(与历史行为一致) - /// 2. 主扫/H5 等免 openId 方式: 仅当存在 openId 黑名单且当前 clientEnv 可 OAuth 时 true, + /// 2. 主扫/H5 等免 openId 方式: 仅当 openId 拦截级别为 ENHANCED, + /// 且存在 openId 黑名单, 且当前 clientEnv 可 OAuth 时 true, /// 实现 openId 黑名单在聚合网关内的全局拦截 private boolean resolveNeedOpenId(String method, ClientEnvEnum clientEnv) { if (PayMethodOpenIdSupport.needsOpenId(method)) { return true; } PayRiskChecker checker = payRiskCheckerProvider.getIfAvailable(); - if (checker == null || !checker.hasOpenIdBlacklist()) { + if (checker == null || !isEnhancedOpenIdLevel() || !checker.hasOpenIdBlacklist()) { return false; } return PayMethodOpenIdSupport.canAcquireOpenId(method, clientEnv); } + + /// openId 拦截级别是否为增强模式(NORMAL 时跳过强制 OAuth, 保留用户体验) + private boolean isEnhancedOpenIdLevel() { + String level = platformSecurityConfigService.getPaySecurityConfig().getRiskOpenIdLevel(); + return PayRiskOpenIdLevelEnum.ENHANCED.getCode().equals(level); + } } diff --git a/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/trade/runtime/service/pay/gateway/CashierPayService.java b/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/trade/runtime/service/pay/gateway/CashierPayService.java index 290745e0b..3829b3c24 100644 --- a/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/trade/runtime/service/pay/gateway/CashierPayService.java +++ b/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/trade/runtime/service/pay/gateway/CashierPayService.java @@ -16,6 +16,8 @@ import cn.daxpay.open.platform.common.spring.util.WebServletUtil; import cn.daxpay.open.platform.core.code.CommonErrorCode; import cn.daxpay.open.platform.core.exception.BizInfoException; import cn.daxpay.open.platform.core.exception.DataNotExistException; +import cn.daxpay.open.platform.system.enums.PayRiskOpenIdLevelEnum; +import cn.daxpay.open.platform.system.service.config.security.PlatformSecurityConfigService; import cn.hutool.core.util.StrUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -48,6 +50,8 @@ public class CashierPayService { private final GatewayCashierItemManager gatewayCashierItemManager; /// 风控检查器(可选 SPI:用于判断是否存在 openId 黑名单, 决定是否触发强制 OAuth) private final ObjectProvider payRiskCheckerProvider; + /// 平台安全配置(读取 openId 拦截级别, 决定 NORMAL 模式下不触发强制 OAuth) + private final PlatformSecurityConfigService platformSecurityConfigService; /// 公开支付项列表(落地页展示) public List listPublicItems(String orderNo, String cashierType, String clientEnv) { @@ -168,15 +172,22 @@ public class CashierPayService { /// openId 触发判定(与聚合/码牌同源逻辑) /// /// 1. JSAPI/MINI 类方式: 业务必需, 永远 true - /// 2. 主扫/H5 等免 openId 方式: 仅当存在 openId 黑名单且当前 clientEnv 可 OAuth 时 true + /// 2. 主扫/H5 等免 openId 方式: 仅当 openId 拦截级别为 ENHANCED, + /// 且存在 openId 黑名单且当前 clientEnv 可 OAuth 时 true private boolean resolveItemNeedOpenId(String method, ClientEnvEnum clientEnv) { if (PayMethodOpenIdSupport.needsOpenId(method)) { return true; } PayRiskChecker checker = payRiskCheckerProvider.getIfAvailable(); - if (checker == null || !checker.hasOpenIdBlacklist()) { + if (checker == null || !isEnhancedOpenIdLevel() || !checker.hasOpenIdBlacklist()) { return false; } return PayMethodOpenIdSupport.canAcquireOpenId(method, clientEnv); } + + /// openId 拦截级别是否为增强模式(NORMAL 时跳过强制 OAuth, 保留用户体验) + private boolean isEnhancedOpenIdLevel() { + String level = platformSecurityConfigService.getPaySecurityConfig().getRiskOpenIdLevel(); + return PayRiskOpenIdLevelEnum.ENHANCED.getCode().equals(level); + } } diff --git a/daxpay-payment/daxpay-payment-unipay/src/main/java/cn/daxpay/open/payment/unipay/client/service/CodePayAssistService.java b/daxpay-payment/daxpay-payment-unipay/src/main/java/cn/daxpay/open/payment/unipay/client/service/CodePayAssistService.java index 0afed00de..06aa2c64f 100644 --- a/daxpay-payment/daxpay-payment-unipay/src/main/java/cn/daxpay/open/payment/unipay/client/service/CodePayAssistService.java +++ b/daxpay-payment/daxpay-payment-unipay/src/main/java/cn/daxpay/open/payment/unipay/client/service/CodePayAssistService.java @@ -37,6 +37,8 @@ import cn.daxpay.open.platform.core.exception.BizInfoException; import cn.daxpay.open.platform.core.exception.DataNotExistException; import cn.daxpay.open.platform.core.exception.operation.OperationFailException; import cn.daxpay.open.platform.core.util.TradeNoGenerateUtil; +import cn.daxpay.open.platform.system.enums.PayRiskOpenIdLevelEnum; +import cn.daxpay.open.platform.system.service.config.security.PlatformSecurityConfigService; import cn.hutool.core.util.StrUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -64,6 +66,8 @@ public class CodePayAssistService { private final NormalPayOrderManager normalPayOrderManager; /// 风控检查器(可选 SPI:用于判断是否存在 openId 黑名单, 决定是否触发强制 OAuth) private final ObjectProvider payRiskCheckerProvider; + /// 平台安全配置(读取 openId 拦截级别, 决定 NORMAL 模式下不触发强制 OAuth) + private final PlatformSecurityConfigService platformSecurityConfigService; /// 根据码牌编码查询支付信息(公开接口, 脱敏返回) /// @@ -268,19 +272,26 @@ public class CodePayAssistService { /// openId 触发判定 /// /// 1. JSAPI/MINI 类方式: 业务必需, 永远 true(与历史行为一致) - /// 2. 主扫/H5 等免 openId 方式: 仅当存在 openId 黑名单且当前 clientEnv 可 OAuth 时 true, + /// 2. 主扫/H5 等免 openId 方式: 仅当 openId 拦截级别为 ENHANCED, + /// 且存在 openId 黑名单且当前 clientEnv 可 OAuth 时 true, /// 实现 openId 黑名单在码牌场景的全局拦截 private boolean resolveNeedOpenId(String method, ClientEnvEnum clientEnv) { if (PayMethodOpenIdSupport.needsOpenId(method)) { return true; } PayRiskChecker checker = payRiskCheckerProvider.getIfAvailable(); - if (checker == null || !checker.hasOpenIdBlacklist()) { + if (checker == null || !isEnhancedOpenIdLevel() || !checker.hasOpenIdBlacklist()) { return false; } return PayMethodOpenIdSupport.canAcquireOpenId(method, clientEnv); } + /// openId 拦截级别是否为增强模式(NORMAL 时跳过强制 OAuth, 保留用户体验) + private boolean isEnhancedOpenIdLevel() { + String level = platformSecurityConfigService.getPaySecurityConfig().getRiskOpenIdLevel(); + return PayRiskOpenIdLevelEnum.ENHANCED.getCode().equals(level); + } + /// 分端页 returnPath: /h/wechat|{alipay}/:code?authed=1 private String buildReturnPath(ClientEnvEnum clientEnv, String code) { String segment = switch (clientEnv) { diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/en-US/enum/pay_risk_open_id_level.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/en-US/enum/pay_risk_open_id_level.json new file mode 100644 index 000000000..6863976e9 --- /dev/null +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/en-US/enum/pay_risk_open_id_level.json @@ -0,0 +1,4 @@ +{ + "normal": "Normal", + "enhanced": "Enhanced" +} diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/en-US/validation.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/en-US/validation.json index 8b7eb74b7..0e732953e 100644 --- a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/en-US/validation.json +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/en-US/validation.json @@ -791,6 +791,12 @@ "riskCheckAfterPay": { "notNull": "Post-pay logging toggle cannot be empty" }, + "riskOpenIdLevel": { + "notNull": "openId interception level cannot be empty" + }, + "blockOverseasIp": { + "notNull": "Overseas IP block toggle cannot be empty" + }, "reqId": { "notBlank": "Request ID is required", "size": "Request ID must not exceed 64 characters" diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/id-ID/enum/pay_risk_open_id_level.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/id-ID/enum/pay_risk_open_id_level.json new file mode 100644 index 000000000..ad01ee54e --- /dev/null +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/id-ID/enum/pay_risk_open_id_level.json @@ -0,0 +1,4 @@ +{ + "normal": "Blokir Normal", + "enhanced": "Blokir Ditingkatkan" +} diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/id-ID/validation.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/id-ID/validation.json index 3a5577a57..5b414fa5c 100644 --- a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/id-ID/validation.json +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/id-ID/validation.json @@ -797,6 +797,12 @@ }, "riskCheckAfterPay": { "notNull": "Pilihan pemeriksaan setelah pembayaran wajib diisi" + }, + "riskOpenIdLevel": { + "notNull": "Level intercept openId tidak boleh kosong" + }, + "blockOverseasIp": { + "notNull": "Saklar blokir IP luar negeri tidak boleh kosong" } } } diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ja-JP/enum/pay_risk_open_id_level.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ja-JP/enum/pay_risk_open_id_level.json new file mode 100644 index 000000000..079c39f27 --- /dev/null +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ja-JP/enum/pay_risk_open_id_level.json @@ -0,0 +1,4 @@ +{ + "normal": "通常ブロック", + "enhanced": "強化ブロック" +} diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ja-JP/validation.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ja-JP/validation.json index 16a1e17b3..61efab04f 100644 --- a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ja-JP/validation.json +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ja-JP/validation.json @@ -791,6 +791,12 @@ "riskCheckAfterPay": { "notNull": "決済後記録スイッチは必須です" }, + "riskOpenIdLevel": { + "notNull": "openId ブロック レベルは必須です" + }, + "blockOverseasIp": { + "notNull": "海外 IP ブロック スイッチは必須です" + }, "reqId": { "notBlank": "リクエストIDは必須です", "size": "リクエストIDは64文字以内です" diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ko-KR/enum/pay_risk_open_id_level.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ko-KR/enum/pay_risk_open_id_level.json new file mode 100644 index 000000000..00d20c5d8 --- /dev/null +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ko-KR/enum/pay_risk_open_id_level.json @@ -0,0 +1,4 @@ +{ + "normal": "일반 차단", + "enhanced": "강화 차단" +} diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ko-KR/validation.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ko-KR/validation.json index 2dc5a89f4..3ebaee25c 100644 --- a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ko-KR/validation.json +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ko-KR/validation.json @@ -791,6 +791,12 @@ "riskCheckAfterPay": { "notNull": "결제 후 기록 스위치는 필수입니다" }, + "riskOpenIdLevel": { + "notNull": "openId 차단 레벨은 필수입니다" + }, + "blockOverseasIp": { + "notNull": "해외 IP 차단 스위치는 필수입니다" + }, "reqId": { "notBlank": "요청 ID는 필수입니다", "size": "요청 ID는 64자를 초과할 수 없습니다" diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ms-MY/enum/pay_risk_open_id_level.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ms-MY/enum/pay_risk_open_id_level.json new file mode 100644 index 000000000..e44cb969c --- /dev/null +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ms-MY/enum/pay_risk_open_id_level.json @@ -0,0 +1,4 @@ +{ + "normal": "Sekatan Biasa", + "enhanced": "Sekatan Diperkuat" +} diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ms-MY/validation.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ms-MY/validation.json index 60bd2e3d3..833bca02b 100644 --- a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ms-MY/validation.json +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ms-MY/validation.json @@ -797,6 +797,12 @@ }, "riskCheckAfterPay": { "notNull": "Pilihan semakan selepas pembayaran tidak boleh kosong" + }, + "riskOpenIdLevel": { + "notNull": "Tahap sekatan openId tidak boleh kosong" + }, + "blockOverseasIp": { + "notNull": "Suis sekatan IP luar negara tidak boleh kosong" } } } diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/th-TH/enum/pay_risk_open_id_level.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/th-TH/enum/pay_risk_open_id_level.json new file mode 100644 index 000000000..2098f741d --- /dev/null +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/th-TH/enum/pay_risk_open_id_level.json @@ -0,0 +1,4 @@ +{ + "normal": "บล็อกปกติ", + "enhanced": "บล็อกเข้มข้น" +} diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/th-TH/validation.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/th-TH/validation.json index 672052a92..f91e63964 100644 --- a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/th-TH/validation.json +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/th-TH/validation.json @@ -797,6 +797,12 @@ }, "riskCheckAfterPay": { "notNull": "ตัวเลือกการตรวจสอบหลังชำระเงินต้องไม่เป็นค่าว่าง" + }, + "riskOpenIdLevel": { + "notNull": "ระดับการบล็อก openId ต้องไม่ว่าง" + }, + "blockOverseasIp": { + "notNull": "สวิตช์บล็อก IP ต่างประเทศต้องไม่ว่าง" } } } diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/vi-VN/enum/pay_risk_open_id_level.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/vi-VN/enum/pay_risk_open_id_level.json new file mode 100644 index 000000000..61f02d7de --- /dev/null +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/vi-VN/enum/pay_risk_open_id_level.json @@ -0,0 +1,4 @@ +{ + "normal": "Chặn Bình Thường", + "enhanced": "Chặn Tăng Cường" +} diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/vi-VN/validation.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/vi-VN/validation.json index ac55613e1..7fd189ec2 100644 --- a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/vi-VN/validation.json +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/vi-VN/validation.json @@ -797,6 +797,12 @@ }, "riskCheckAfterPay": { "notNull": "Tùy chọn kiểm tra sau thanh toán là bắt buộc" + }, + "riskOpenIdLevel": { + "notNull": "Cấp độ chặn openId không được để trống" + }, + "blockOverseasIp": { + "notNull": "Công tắc chặn IP nước ngoài không được để trống" } } } diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-CN/enum/pay_risk_open_id_level.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-CN/enum/pay_risk_open_id_level.json new file mode 100644 index 000000000..9a02e0683 --- /dev/null +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-CN/enum/pay_risk_open_id_level.json @@ -0,0 +1,4 @@ +{ + "normal": "正常拦截", + "enhanced": "增强拦截" +} diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-CN/validation.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-CN/validation.json index 455f19eb4..6a2243270 100644 --- a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-CN/validation.json +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-CN/validation.json @@ -791,6 +791,12 @@ "riskCheckAfterPay": { "notNull": "事后补录开关不能为空" }, + "riskOpenIdLevel": { + "notNull": "openId 拦截级别不能为空" + }, + "blockOverseasIp": { + "notNull": "海外 IP 拦截开关不能为空" + }, "reqId": { "notBlank": "请求ID不可为空", "size": "请求ID不可超过64位" diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-HK/enum/pay_risk_open_id_level.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-HK/enum/pay_risk_open_id_level.json new file mode 100644 index 000000000..fcfd19ac6 --- /dev/null +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-HK/enum/pay_risk_open_id_level.json @@ -0,0 +1,4 @@ +{ + "normal": "正常攔截", + "enhanced": "增強攔截" +} diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-HK/validation.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-HK/validation.json index ec6bc7db5..f3b681664 100644 --- a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-HK/validation.json +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-HK/validation.json @@ -791,6 +791,12 @@ "riskCheckAfterPay": { "notNull": "事後補錄開關不能為空" }, + "riskOpenIdLevel": { + "notNull": "openId 攔截級別不能為空" + }, + "blockOverseasIp": { + "notNull": "海外 IP 攔截開關不能為空" + }, "reqId": { "notBlank": "請求ID不可為空", "size": "請求ID不可超過64位" diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-TW/enum/pay_risk_open_id_level.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-TW/enum/pay_risk_open_id_level.json new file mode 100644 index 000000000..fcfd19ac6 --- /dev/null +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-TW/enum/pay_risk_open_id_level.json @@ -0,0 +1,4 @@ +{ + "normal": "正常攔截", + "enhanced": "增強攔截" +} diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-TW/validation.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-TW/validation.json index 7ca6005da..7bc255636 100644 --- a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-TW/validation.json +++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-TW/validation.json @@ -791,6 +791,12 @@ "riskCheckAfterPay": { "notNull": "事後補錄開關不能為空" }, + "riskOpenIdLevel": { + "notNull": "openId 攔截級別不能為空" + }, + "blockOverseasIp": { + "notNull": "海外 IP 攔截開關不能為空" + }, "reqId": { "notBlank": "請求ID不可為空", "size": "請求ID不可超過64位" diff --git a/daxpay-platform/daxpay-platform-service/service-system/src/main/java/cn/daxpay/open/platform/system/entity/config/platform/security/PlatformPaySecurityConfig.java b/daxpay-platform/daxpay-platform-service/service-system/src/main/java/cn/daxpay/open/platform/system/entity/config/platform/security/PlatformPaySecurityConfig.java index d65da6a9b..c93c24301 100644 --- a/daxpay-platform/daxpay-platform-service/service-system/src/main/java/cn/daxpay/open/platform/system/entity/config/platform/security/PlatformPaySecurityConfig.java +++ b/daxpay-platform/daxpay-platform-service/service-system/src/main/java/cn/daxpay/open/platform/system/entity/config/platform/security/PlatformPaySecurityConfig.java @@ -1,5 +1,6 @@ package cn.daxpay.open.platform.system.entity.config.platform.security; +import cn.daxpay.open.platform.system.enums.PayRiskOpenIdLevelEnum; import lombok.Data; import lombok.experimental.Accessors; @@ -12,6 +13,8 @@ import lombok.experimental.Accessors; /// - 风控总开关: 关闭后支付主链路跳过所有风控检查 /// - 命中阻断: 支付前命中黑名单是否拒绝下单(关闭则仅记录不拦截) /// - 事后补录: 支付成功后是否补充记录命中(用于事后分析,不阻断资金态) +/// - openId 拦截级别: 是否对 H5 / 主扫等免 openId 方式强制 OAuth, 见 [PayRiskOpenIdLevelEnum] +/// - 海外 IP 拦截: 占位字段, 后续接入 IP 地理位置库后实现 @Data @Accessors(chain = true) public class PlatformPaySecurityConfig { @@ -24,4 +27,11 @@ public class PlatformPaySecurityConfig { /// 支付成功后是否补录命中(用于事后分析) private Boolean riskCheckAfterPay = Boolean.TRUE; + + /// openId 拦截级别(默认增强拦截, 保持历史行为) + /// @see PayRiskOpenIdLevelEnum + private String riskOpenIdLevel = PayRiskOpenIdLevelEnum.ENHANCED.getCode(); + + /// 海外 IP 拦截(占位字段, 默认关闭, 后续接入地理位置库后实现) + private Boolean blockOverseasIp = Boolean.FALSE; } diff --git a/daxpay-platform/daxpay-platform-service/service-system/src/main/java/cn/daxpay/open/platform/system/enums/PayRiskOpenIdLevelEnum.java b/daxpay-platform/daxpay-platform-service/service-system/src/main/java/cn/daxpay/open/platform/system/enums/PayRiskOpenIdLevelEnum.java new file mode 100644 index 000000000..c5466aba6 --- /dev/null +++ b/daxpay-platform/daxpay-platform-service/service-system/src/main/java/cn/daxpay/open/platform/system/enums/PayRiskOpenIdLevelEnum.java @@ -0,0 +1,36 @@ +package cn.daxpay.open.platform.system.enums; + +import cn.daxpay.open.platform.core.i18n.I18nSupport; +import lombok.Getter; +import lombok.RequiredArgsConstructor; + +import java.util.Arrays; +import java.util.Optional; + +/// # openId 拦截级别 +/// +/// 控制 openId 黑名单对「原本免 openId 支付方式(H5 / 主扫)」是否触发强制 OAuth。 +/// JSAPI / 小程序原生方式业务本身就要 openId, 不受此开关影响。 +/// +/// - [NORMAL]: 仅做 IP + 事后补录, 不为风控额外触发 OAuth(保留用户体验) +/// - [ENHANCED]: 存在 openId 名单时, 对 H5 / 主扫等可 OAuth 方式强制静默授权 +@Getter +@RequiredArgsConstructor +public enum PayRiskOpenIdLevelEnum implements I18nSupport { + + /// 正常拦截(仅 IP + 事后补录) + NORMAL("normal"), + /// 增强拦截(对 H5 / 主扫强制 OAuth) + ENHANCED("enhanced"); + + private final String code; + + @Override + public String getI18nPrefix() { + return "enum.pay_risk_open_id_level"; + } + + public static Optional findByCode(String code) { + return Arrays.stream(values()).filter(e -> e.code.equals(code)).findFirst(); + } +} diff --git a/daxpay-platform/daxpay-platform-service/service-system/src/main/java/cn/daxpay/open/platform/system/param/config/security/PlatformPaySecurityConfigParam.java b/daxpay-platform/daxpay-platform-service/service-system/src/main/java/cn/daxpay/open/platform/system/param/config/security/PlatformPaySecurityConfigParam.java index 88d90f7bd..146f25b33 100644 --- a/daxpay-platform/daxpay-platform-service/service-system/src/main/java/cn/daxpay/open/platform/system/param/config/security/PlatformPaySecurityConfigParam.java +++ b/daxpay-platform/daxpay-platform-service/service-system/src/main/java/cn/daxpay/open/platform/system/param/config/security/PlatformPaySecurityConfigParam.java @@ -23,4 +23,12 @@ public class PlatformPaySecurityConfigParam { @Schema(description = "支付成功后是否补录命中(用于事后分析)") @NotNull(message = "{validation.field.riskCheckAfterPay.notNull}") private Boolean riskCheckAfterPay; + + @Schema(description = "openId 拦截级别(normal=正常拦截 / enhanced=增强拦截)") + @NotNull(message = "{validation.field.riskOpenIdLevel.notNull}") + private String riskOpenIdLevel; + + @Schema(description = "海外 IP 拦截(占位字段, 默认关闭, 后续接入)") + @NotNull(message = "{validation.field.blockOverseasIp.notNull}") + private Boolean blockOverseasIp; } diff --git a/daxpay-platform/daxpay-platform-service/service-system/src/main/java/cn/daxpay/open/platform/system/result/config/security/PlatformPaySecurityConfigResult.java b/daxpay-platform/daxpay-platform-service/service-system/src/main/java/cn/daxpay/open/platform/system/result/config/security/PlatformPaySecurityConfigResult.java index d1755752b..c7dcfaa04 100644 --- a/daxpay-platform/daxpay-platform-service/service-system/src/main/java/cn/daxpay/open/platform/system/result/config/security/PlatformPaySecurityConfigResult.java +++ b/daxpay-platform/daxpay-platform-service/service-system/src/main/java/cn/daxpay/open/platform/system/result/config/security/PlatformPaySecurityConfigResult.java @@ -22,4 +22,10 @@ public class PlatformPaySecurityConfigResult extends BaseResult { @Schema(description = "支付成功后是否补录命中(用于事后分析)") private Boolean riskCheckAfterPay; + + @Schema(description = "openId 拦截级别(normal=正常拦截 / enhanced=增强拦截)") + private String riskOpenIdLevel; + + @Schema(description = "海外 IP 拦截(占位字段, 默认关闭, 后续接入)") + private Boolean blockOverseasIp; } diff --git a/daxpay-platform/daxpay-platform-service/service-system/src/main/java/cn/daxpay/open/platform/system/service/config/security/PlatformSecurityConfigService.java b/daxpay-platform/daxpay-platform-service/service-system/src/main/java/cn/daxpay/open/platform/system/service/config/security/PlatformSecurityConfigService.java index a1a2aa945..3cad38717 100644 --- a/daxpay-platform/daxpay-platform-service/service-system/src/main/java/cn/daxpay/open/platform/system/service/config/security/PlatformSecurityConfigService.java +++ b/daxpay-platform/daxpay-platform-service/service-system/src/main/java/cn/daxpay/open/platform/system/service/config/security/PlatformSecurityConfigService.java @@ -3,6 +3,7 @@ package cn.daxpay.open.platform.system.service.config.security; import cn.daxpay.open.platform.common.json.util.JacksonUtil; import cn.daxpay.open.platform.system.convert.config.security.PlatformSecurityConfigConvert; import cn.daxpay.open.platform.system.entity.config.platform.security.*; +import cn.daxpay.open.platform.system.enums.PayRiskOpenIdLevelEnum; import cn.daxpay.open.platform.system.enums.PlatformConfigTypeEnum; import cn.daxpay.open.platform.system.param.config.security.*; import cn.daxpay.open.platform.system.result.config.security.*; @@ -257,12 +258,14 @@ public class PlatformSecurityConfigService { return config == null ? defaultPaySecurityConfig() : config; } - /// 支付安全配置默认值: 默认开启风控、命中阻断、事后补录 + /// 支付安全配置默认值: 默认开启风控、命中阻断、事后补录、增强拦截 private PlatformPaySecurityConfig defaultPaySecurityConfig() { return new PlatformPaySecurityConfig() .setRiskEnabled(true) .setRiskBlockBeforePay(true) - .setRiskCheckAfterPay(true); + .setRiskCheckAfterPay(true) + .setRiskOpenIdLevel(PayRiskOpenIdLevelEnum.ENHANCED.getCode()) + .setBlockOverseasIp(false); } /// 获取支付安全配置(结果)