diff --git a/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/strategy/risk/PayRiskCheckContext.java b/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/strategy/risk/PayRiskCheckContext.java
index 35e2f33d9..10f2b32cf 100644
--- a/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/strategy/risk/PayRiskCheckContext.java
+++ b/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/strategy/risk/PayRiskCheckContext.java
@@ -57,4 +57,10 @@ public class PayRiskCheckContext {
/// 事前命中是否阻断下单(null/true=阻断;false=仅落命中记录)
private Boolean blockOnHit;
+
+ /// 是否拦截海外 IP(null/false=不拦截;true=拦截)
+ ///
+ /// 地域策略开关快照, 由 [cn.daxpay.open.payment.trade.runtime.service.pay.common.PayRiskAssistService]
+ /// 读取平台配置后注入, 供检查器按 IP 归属地判定是否命中。
+ private Boolean blockOverseasIp;
}
diff --git a/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/trade/runtime/service/pay/common/PayRiskAssistService.java b/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/trade/runtime/service/pay/common/PayRiskAssistService.java
index 626868fdf..13118bba3 100644
--- a/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/trade/runtime/service/pay/common/PayRiskAssistService.java
+++ b/daxpay-payment/daxpay-payment-core/src/main/java/cn/daxpay/open/payment/trade/runtime/service/pay/common/PayRiskAssistService.java
@@ -51,6 +51,8 @@ public class PayRiskAssistService {
PayRiskCheckContext ctx = buildContextFromParam(payParam, scene);
// false=仅记录不拦截;缺省/true=命中拒绝下单
ctx.setBlockOnHit(!Boolean.FALSE.equals(config.getRiskBlockBeforePay()));
+ // 海外 IP 拦截开关(地域策略)
+ ctx.setBlockOverseasIp(config.getBlockOverseasIp());
checker.checkBeforePay(ctx);
}
@@ -68,6 +70,8 @@ public class PayRiskAssistService {
return;
}
PayRiskCheckContext ctx = buildContextFromTrade(trade);
+ // 海外 IP 拦截开关(地域策略, 事后仅记录海外访问)
+ ctx.setBlockOverseasIp(config.getBlockOverseasIp());
if (StrUtil.isNotBlank(buyerId)) {
ctx.setBuyerId(buyerId);
}
diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/en-US/enum/pay_blacklist_type.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/en-US/enum/pay_blacklist_type.json
index 55767a83a..a9fb43a74 100644
--- a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/en-US/enum/pay_blacklist_type.json
+++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/en-US/enum/pay_blacklist_type.json
@@ -1,5 +1,6 @@
{
"ip": "IP",
"alipay_user": "Alipay user",
- "wechat_openid": "WeChat OpenId"
+ "wechat_openid": "WeChat OpenId",
+ "overseas_ip": "Overseas IP"
}
diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/id-ID/enum/pay_blacklist_type.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/id-ID/enum/pay_blacklist_type.json
index ad4167299..8d3541b7c 100644
--- a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/id-ID/enum/pay_blacklist_type.json
+++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/id-ID/enum/pay_blacklist_type.json
@@ -1,5 +1,6 @@
{
"ip": "IP",
"alipay_user": "Pengguna Alipay",
- "wechat_openid": "OpenId WeChat"
+ "wechat_openid": "OpenId WeChat",
+ "overseas_ip": "IP Luar Negeri"
}
diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ja-JP/enum/pay_blacklist_type.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ja-JP/enum/pay_blacklist_type.json
index 9694d3917..ccbd93a73 100644
--- a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ja-JP/enum/pay_blacklist_type.json
+++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ja-JP/enum/pay_blacklist_type.json
@@ -1,5 +1,6 @@
{
"ip": "IP",
"alipay_user": "Alipay ユーザー",
- "wechat_openid": "WeChat OpenId"
+ "wechat_openid": "WeChat OpenId",
+ "overseas_ip": "海外IP"
}
diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ko-KR/enum/pay_blacklist_type.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ko-KR/enum/pay_blacklist_type.json
index d7716e9c3..ebc344e51 100644
--- a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ko-KR/enum/pay_blacklist_type.json
+++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ko-KR/enum/pay_blacklist_type.json
@@ -1,5 +1,6 @@
{
"ip": "IP",
"alipay_user": "알리페이 사용자",
- "wechat_openid": "위챗 OpenId"
+ "wechat_openid": "위챗 OpenId",
+ "overseas_ip": "해외 IP"
}
diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ms-MY/enum/pay_blacklist_type.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ms-MY/enum/pay_blacklist_type.json
index ad4167299..84f1b9630 100644
--- a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ms-MY/enum/pay_blacklist_type.json
+++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/ms-MY/enum/pay_blacklist_type.json
@@ -1,5 +1,6 @@
{
"ip": "IP",
"alipay_user": "Pengguna Alipay",
- "wechat_openid": "OpenId WeChat"
+ "wechat_openid": "OpenId WeChat",
+ "overseas_ip": "IP Luar Negara"
}
diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/th-TH/enum/pay_blacklist_type.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/th-TH/enum/pay_blacklist_type.json
index 8bef83a47..573fbf587 100644
--- a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/th-TH/enum/pay_blacklist_type.json
+++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/th-TH/enum/pay_blacklist_type.json
@@ -1,5 +1,6 @@
{
"ip": "IP",
"alipay_user": "ผู้ใช้ Alipay",
- "wechat_openid": "OpenId WeChat"
+ "wechat_openid": "OpenId WeChat",
+ "overseas_ip": "IP ต่างประเทศ"
}
diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/vi-VN/enum/pay_blacklist_type.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/vi-VN/enum/pay_blacklist_type.json
index 4959ef2c6..8acc59747 100644
--- a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/vi-VN/enum/pay_blacklist_type.json
+++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/vi-VN/enum/pay_blacklist_type.json
@@ -1,5 +1,6 @@
{
"ip": "IP",
"alipay_user": "Người dùng Alipay",
- "wechat_openid": "OpenId WeChat"
+ "wechat_openid": "OpenId WeChat",
+ "overseas_ip": "IP nước ngoài"
}
diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-CN/enum/pay_blacklist_type.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-CN/enum/pay_blacklist_type.json
index 38e0a115d..7d0172269 100644
--- a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-CN/enum/pay_blacklist_type.json
+++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-CN/enum/pay_blacklist_type.json
@@ -1,5 +1,6 @@
{
"ip": "IP",
"alipay_user": "支付宝用户",
- "wechat_openid": "微信 OpenId"
+ "wechat_openid": "微信 OpenId",
+ "overseas_ip": "海外IP"
}
diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-HK/enum/pay_blacklist_type.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-HK/enum/pay_blacklist_type.json
index d01e26988..08c48b60b 100644
--- a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-HK/enum/pay_blacklist_type.json
+++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-HK/enum/pay_blacklist_type.json
@@ -1,5 +1,6 @@
{
"ip": "IP",
"alipay_user": "支付寶用戶",
- "wechat_openid": "微信 OpenId"
+ "wechat_openid": "微信 OpenId",
+ "overseas_ip": "海外IP"
}
diff --git a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-TW/enum/pay_blacklist_type.json b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-TW/enum/pay_blacklist_type.json
index d01e26988..08c48b60b 100644
--- a/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-TW/enum/pay_blacklist_type.json
+++ b/daxpay-platform/daxpay-platform-common/common-i18n/src/main/resources/i18n/zh-TW/enum/pay_blacklist_type.json
@@ -1,5 +1,6 @@
{
"ip": "IP",
"alipay_user": "支付寶用戶",
- "wechat_openid": "微信 OpenId"
+ "wechat_openid": "微信 OpenId",
+ "overseas_ip": "海外IP"
}
diff --git a/daxpay-plugin/daxpay-plugin-risk/pom.xml b/daxpay-plugin/daxpay-plugin-risk/pom.xml
index 65bb04b31..8b2fafc1d 100644
--- a/daxpay-plugin/daxpay-plugin-risk/pom.xml
+++ b/daxpay-plugin/daxpay-plugin-risk/pom.xml
@@ -11,4 +11,13 @@
daxpay-plugin-risk
jar
支付风控插件(黑名单配置 + 命中记录)
+
+
+
+
+ cn.daxpay.open
+ capability-audit-log
+ ${project.version}
+
+
diff --git a/daxpay-plugin/daxpay-plugin-risk/src/main/java/cn/daxpay/open/plugin/risk/enums/PayBlacklistTypeEnum.java b/daxpay-plugin/daxpay-plugin-risk/src/main/java/cn/daxpay/open/plugin/risk/enums/PayBlacklistTypeEnum.java
index d4d2f74b0..65edaf1de 100644
--- a/daxpay-plugin/daxpay-plugin-risk/src/main/java/cn/daxpay/open/plugin/risk/enums/PayBlacklistTypeEnum.java
+++ b/daxpay-plugin/daxpay-plugin-risk/src/main/java/cn/daxpay/open/plugin/risk/enums/PayBlacklistTypeEnum.java
@@ -18,7 +18,9 @@ public enum PayBlacklistTypeEnum implements I18nSupport {
/// 支付宝用户(userId,通道内全局)
ALIPAY_USER("alipay_user"),
/// 微信 OpenId(绑定平台支付应用)
- WECHAT_OPENID("wechat_openid");
+ WECHAT_OPENID("wechat_openid"),
+ /// 海外 IP(地域策略命中, 非黑名单来源)
+ OVERSEAS_IP("overseas_ip");
private final String code;
diff --git a/daxpay-plugin/daxpay-plugin-risk/src/main/java/cn/daxpay/open/plugin/risk/service/PayBlacklistService.java b/daxpay-plugin/daxpay-plugin-risk/src/main/java/cn/daxpay/open/plugin/risk/service/PayBlacklistService.java
index 142b00e33..985b65a79 100644
--- a/daxpay-plugin/daxpay-plugin-risk/src/main/java/cn/daxpay/open/plugin/risk/service/PayBlacklistService.java
+++ b/daxpay-plugin/daxpay-plugin-risk/src/main/java/cn/daxpay/open/plugin/risk/service/PayBlacklistService.java
@@ -166,6 +166,10 @@ public class PayBlacklistService {
/// 将命中快照映射为名单 type + wxAppId;微信缺 AppId 则返回 null
private ResolvedIdentity resolveIdentity(String hitType, String channel, String wxAppId) {
+ // 海外 IP 命中加黑: 映射为普通 IP 黑名单(持续拉黑该具体 IP)
+ if (PayBlacklistTypeEnum.OVERSEAS_IP.getCode().equals(hitType)) {
+ return new ResolvedIdentity(PayBlacklistTypeEnum.IP.getCode(), null);
+ }
if (PayBlacklistTypeEnum.IP.getCode().equals(hitType)) {
return new ResolvedIdentity(PayBlacklistTypeEnum.IP.getCode(), null);
}
diff --git a/daxpay-plugin/daxpay-plugin-risk/src/main/java/cn/daxpay/open/plugin/risk/strategy/DefaultPayRiskChecker.java b/daxpay-plugin/daxpay-plugin-risk/src/main/java/cn/daxpay/open/plugin/risk/strategy/DefaultPayRiskChecker.java
index 0529c8995..079b51d16 100644
--- a/daxpay-plugin/daxpay-plugin-risk/src/main/java/cn/daxpay/open/plugin/risk/strategy/DefaultPayRiskChecker.java
+++ b/daxpay-plugin/daxpay-plugin-risk/src/main/java/cn/daxpay/open/plugin/risk/strategy/DefaultPayRiskChecker.java
@@ -4,6 +4,8 @@ import cn.daxpay.open.payment.strategy.risk.PayRiskCheckContext;
import cn.daxpay.open.payment.strategy.risk.PayRiskChecker;
import cn.daxpay.open.platform.core.code.PayErrorCode;
import cn.daxpay.open.platform.core.enums.pay.channel.ChannelEnum;
+import cn.daxpay.open.platform.capability.audit.log.service.ip2region.IpRegion;
+import cn.daxpay.open.platform.capability.audit.log.service.ip2region.IpToRegionService;
import cn.daxpay.open.platform.core.exception.BizInfoException;
import cn.daxpay.open.plugin.risk.entity.PayBlacklist;
import cn.daxpay.open.plugin.risk.enums.PayBlacklistTypeEnum;
@@ -31,6 +33,7 @@ public class DefaultPayRiskChecker implements PayRiskChecker {
private final PayBlacklistService payBlacklistService;
private final PayRiskHitService payRiskHitService;
+ private final IpToRegionService ipToRegionService;
/// 用户标识黑名单存在性缓存(短 TTL 30s)
///
@@ -60,6 +63,10 @@ public class DefaultPayRiskChecker implements PayRiskChecker {
+ "tradeType={}, method={}, mchNo={}, clientIp={}",
ctx.getTradeType(), ctx.getMethod(), ctx.getMchNo(), ctx.getClientIp());
}
+ // 海外 IP 拦截(地域策略, 非黑名单)
+ if (Boolean.TRUE.equals(ctx.getBlockOverseasIp())) {
+ checkOverseasIp(ctx, throwOnHit);
+ }
}
@Override
@@ -75,6 +82,10 @@ public class DefaultPayRiskChecker implements PayRiskChecker {
if (StrUtil.isNotBlank(ctx.getBuyerId()) && !StrUtil.equals(ctx.getBuyerId(), ctx.getOpenId())) {
checkUserIdentity(ctx, ctx.getBuyerId(), false);
}
+ // 海外 IP 访问记录(事后仅记录, 不阻断)
+ if (Boolean.TRUE.equals(ctx.getBlockOverseasIp())) {
+ checkOverseasIp(ctx, false);
+ }
}
@Override
@@ -127,4 +138,29 @@ public class DefaultPayRiskChecker implements PayRiskChecker {
}
return true;
}
+
+ /// 海外 IP 地域拦截(country≠中国, 港澳台放行; 未知/内网 fail-open)
+ ///
+ /// 与黑名单不同, 海外命中不关联名单行(blacklistId=null), 命中类型为 [PayBlacklistTypeEnum#OVERSEAS_IP]。
+ private void checkOverseasIp(PayRiskCheckContext ctx, boolean throwOnHit) {
+ String ip = ctx.getClientIp();
+ if (StrUtil.isBlank(ip)) {
+ return;
+ }
+ IpRegion region = ipToRegionService.getRegionByIp(ip);
+ // 未知(IPv6/查询失败)/ 内网 / 国内(含港澳台) → 放行
+ if (region == null || region.isInnerIp() || region.isChinaIp()) {
+ return;
+ }
+ // 海外 → 命中记录(blacklistId=null, 非黑名单来源)
+ try {
+ payRiskHitService.recordHit(ctx, PayBlacklistTypeEnum.OVERSEAS_IP.getCode(), ip, null);
+ } catch (Exception e) {
+ log.warn("记录海外IP命中失败 ip={}: {}", ip, e.getMessage());
+ }
+ if (throwOnHit) {
+ // 交易被限制(模糊文案,防探测)
+ throw new BizInfoException(PayErrorCode.OPERATION_FAIL, "pay.error.risk.blacklist");
+ }
+ }
}