mirror of
https://gitee.com/dromara/dax-pay
synced 2026-08-10 14:56:06 +08:00
feat(wechat): 通道认证改走 capability-wechat
直连/服务商 AuthStrategy 调用 WechatMpAuthService 获取 openId, 不再经 channel-one 支付客户端;补充 authAppType 与应用查询方法。
This commit is contained in:
@@ -20,7 +20,8 @@ import org.springframework.web.service.annotation.PostExchange;
|
||||
|
||||
/// # 微信通道客户端
|
||||
///
|
||||
/// 声明式 HTTP 接口, 调用子应用 dax-pay-channel-one 的微信通道接口。
|
||||
/// 声明式 HTTP 接口, 调用子应用 dax-pay-channel-one 的微信**支付**通道接口。
|
||||
/// 公众号/小程序 OAuth 认证见 capability-wechat, 不经本客户端。
|
||||
@HttpExchange(accept = MediaType.APPLICATION_JSON_VALUE, contentType = MediaType.APPLICATION_JSON_VALUE)
|
||||
public interface WechatChannelClient {
|
||||
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package cn.daxpay.open.channel.wechat.code;
|
||||
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/// # 微信服务商认证应用类型
|
||||
///
|
||||
/// 服务商模式下授权获取 openId 时, 控制使用服务商应用还是子商户应用。
|
||||
/// 配置挂在特约商户维度([cn.daxpay.open.channel.wechat.entity.isv.WechatIsvChannelMerchant]), 默认 SP_APP。
|
||||
@Getter
|
||||
@RequiredArgsConstructor
|
||||
public enum WechatAuthAppTypeEnum {
|
||||
|
||||
/// 服务商应用(WechatIsvApp.sp_appid)
|
||||
SP_APP("SP_APP"),
|
||||
/// 子商户应用(WechatIsvMchApp.sub_appid)
|
||||
SUB_APP("SUB_APP");
|
||||
|
||||
/// 编码
|
||||
private final String code;
|
||||
}
|
||||
@@ -41,6 +41,13 @@ public class WechatDirectAppManager extends BaseManager<WechatDirectAppMapper, W
|
||||
.orderByAsc(WechatDirectApp::getId));
|
||||
}
|
||||
|
||||
/// 按通道商户号与wxAppId查询应用(opAppId显式指定认证应用时使用, 校验该appId在系统中预配过)
|
||||
public Optional<WechatDirectApp> findByChannelMchNoAndWxAppId(String channelMchNo, String wxAppId) {
|
||||
return firstOpt(q -> q
|
||||
.eq(WechatDirectApp::getChannelMchNo, channelMchNo)
|
||||
.eq(WechatDirectApp::getWxAppId, wxAppId));
|
||||
}
|
||||
|
||||
/// 校验同一通道商户下wxAppId是否已存在(排除自身)
|
||||
public boolean existsByChannelMchNoAndWxAppId(String mchNo, String channelMchNo, String wxAppId, Long excludeId) {
|
||||
return lambdaQuery()
|
||||
|
||||
@@ -39,6 +39,11 @@ public class WechatIsvAppManager extends BaseManager<WechatIsvAppMapper, WechatI
|
||||
.orderByAsc(WechatIsvApp::getId));
|
||||
}
|
||||
|
||||
/// 按 wxAppId 查询应用(opAppId显式指定认证应用时使用, 校验该appId在系统中预配过)
|
||||
public Optional<WechatIsvApp> findByWxAppId(String wxAppId) {
|
||||
return firstOpt(q -> q.eq(WechatIsvApp::getWxAppId, wxAppId));
|
||||
}
|
||||
|
||||
/// 校验微信应用AppId是否已存在(排除自身)
|
||||
public boolean existsByWxAppId(String wxAppId, Long excludeId) {
|
||||
return lambdaQuery()
|
||||
|
||||
@@ -42,6 +42,13 @@ public class WechatIsvMchAppManager extends BaseManager<WechatIsvMchAppMapper, W
|
||||
.orderByAsc(WechatIsvMchApp::getId));
|
||||
}
|
||||
|
||||
/// 按通道商户号与wxAppId查询应用(opAppId显式指定认证应用时使用, 校验该appId在系统中预配过)
|
||||
public Optional<WechatIsvMchApp> findByChannelMchNoAndWxAppId(String channelMchNo, String wxAppId) {
|
||||
return firstOpt(q -> q
|
||||
.eq(WechatIsvMchApp::getChannelMchNo, channelMchNo)
|
||||
.eq(WechatIsvMchApp::getWxAppId, wxAppId));
|
||||
}
|
||||
|
||||
/// 校验同一通道商户下wxAppId是否已存在(排除自身)
|
||||
public boolean existsByChannelMchNoAndWxAppId(String mchNo, String channelMchNo, String wxAppId, Long excludeId) {
|
||||
return lambdaQuery()
|
||||
|
||||
@@ -30,6 +30,11 @@ public class WechatIsvChannelMerchant extends MchBaseEntity implements ToResult<
|
||||
/// 微信特约商户号/二级商户号(V3 服务商支付 sub_mchid)
|
||||
private String subMchId;
|
||||
|
||||
/// 认证应用类型(服务商模式下授权获取openId时使用)
|
||||
/// SP_APP=服务商应用(sp_appid), SUB_APP=子商户应用(sub_appid), 默认 SP_APP
|
||||
/// @see cn.daxpay.open.channel.wechat.code.WechatAuthAppTypeEnum
|
||||
private String authAppType;
|
||||
|
||||
/// 转换
|
||||
@Override
|
||||
public WechatIsvChannelMerchantResult toResult() {
|
||||
|
||||
@@ -31,4 +31,9 @@ public class WechatIsvChannelMerchantCreateParam {
|
||||
@Schema(description = "微信特约商户号/二级商户号")
|
||||
@NotBlank(message = "{validation.field.subMchId.notBlank}")
|
||||
private String subMchId;
|
||||
|
||||
/// 认证应用类型(SP_APP=服务商应用, SUB_APP=子商户应用), 不传默认 SP_APP
|
||||
/// @see cn.daxpay.open.channel.wechat.code.WechatAuthAppTypeEnum
|
||||
@Schema(description = "认证应用类型(默认SP_APP)")
|
||||
private String authAppType;
|
||||
}
|
||||
|
||||
@@ -24,4 +24,9 @@ public class WechatIsvChannelMerchantResult extends MchTradeBaseResult {
|
||||
|
||||
@Schema(description = "微信特约商户号/二级商户号")
|
||||
private String subMchId;
|
||||
|
||||
/// 认证应用类型(SP_APP=服务商应用, SUB_APP=子商户应用, 默认 SP_APP)
|
||||
/// @see cn.daxpay.open.channel.wechat.code.WechatAuthAppTypeEnum
|
||||
@Schema(description = "认证应用类型")
|
||||
private String authAppType;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package cn.daxpay.open.channel.wechat.service.isv;
|
||||
|
||||
import cn.daxpay.open.channel.wechat.code.WechatAuthAppTypeEnum;
|
||||
import cn.daxpay.open.channel.wechat.dao.isv.WechatIsvChannelMerchantManager;
|
||||
import cn.daxpay.open.channel.wechat.entity.isv.WechatIsvChannelMerchant;
|
||||
import cn.daxpay.open.channel.wechat.param.isv.WechatIsvChannelMerchantCreateParam;
|
||||
@@ -11,6 +12,7 @@ import cn.daxpay.open.platform.core.enums.channel.ChannelMerchantSourceEnum;
|
||||
import cn.daxpay.open.platform.core.exception.BizInfoException;
|
||||
import cn.daxpay.open.platform.core.exception.DataNotExistException;
|
||||
import cn.daxpay.open.platform.core.util.ChannelMchNoGenerateUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -55,6 +57,10 @@ public class WechatIsvChannelMerchantService {
|
||||
entity.setChannelMchNo(channelMchNo);
|
||||
entity.setProduct(param.getProduct());
|
||||
entity.setSubMchId(param.getSubMchId());
|
||||
// 认证应用类型: 不传默认 SP_APP(服务商应用), 认证策略据此路由 sp/sub 应用
|
||||
entity.setAuthAppType(StrUtil.isNotBlank(param.getAuthAppType())
|
||||
? param.getAuthAppType()
|
||||
: WechatAuthAppTypeEnum.SP_APP.getCode());
|
||||
wechatIsvChannelMerchantManager.save(entity);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
package cn.daxpay.open.channel.wechat.strategy.direct;
|
||||
|
||||
import cn.daxpay.open.channel.wechat.dao.direct.WechatDirectAppManager;
|
||||
import cn.daxpay.open.channel.wechat.entity.direct.WechatDirectApp;
|
||||
import cn.daxpay.open.channel.wechat.entity.direct.WechatDirectAppAuthConfig;
|
||||
import cn.daxpay.open.channel.wechat.service.direct.WechatDirectAppAuthConfigService;
|
||||
import cn.daxpay.open.channel.wechat.service.direct.WechatDirectAppCapabilityService;
|
||||
import cn.daxpay.open.payment.core.assist.AuthSession;
|
||||
import cn.daxpay.open.payment.core.strategy.auth.AbsChannelAuthStrategy;
|
||||
import cn.daxpay.open.payment.unipay.param.assist.AuthCodeParam;
|
||||
import cn.daxpay.open.payment.unipay.param.assist.GenerateAuthUrlParam;
|
||||
import cn.daxpay.open.payment.unipay.result.assist.AuthResult;
|
||||
import cn.daxpay.open.payment.unipay.result.assist.AuthUrlResult;
|
||||
import cn.daxpay.open.platform.capability.wechat.auth.result.WechatAuthResult;
|
||||
import cn.daxpay.open.platform.capability.wechat.auth.result.WechatAuthUrlResult;
|
||||
import cn.daxpay.open.platform.capability.wechat.auth.service.WechatMpAuthService;
|
||||
import cn.daxpay.open.platform.core.code.CommonErrorCode;
|
||||
import cn.daxpay.open.platform.core.code.DaxPayErrorCode;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import cn.daxpay.open.platform.core.exception.BizInfoException;
|
||||
import cn.daxpay.open.platform.system.service.config.PlatformUrlConfigService;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/// # 微信直连认证策略
|
||||
///
|
||||
/// 微信直连模式(WECHAT_PAY)下获取用户标识(openId)。复用支付的商户配置体系定位直连应用
|
||||
/// (WechatDirectApp + WechatDirectAppAuthConfig), 调用 capability-wechat 完成 OAuth。
|
||||
///
|
||||
/// ## appId 解析优先级
|
||||
/// 1. opAppId 显式指定 → 校验该 appId 在系统预配过(按 channelMchNo + wxAppId 查), 命中即用
|
||||
/// 2. 否则按 capability 自动解析(显式能力配置 > appType 推导 > 首个兜底)
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class WechatDirectAuthStrategy extends AbsChannelAuthStrategy {
|
||||
|
||||
private final WechatMpAuthService wechatMpAuthService;
|
||||
private final WechatDirectAppCapabilityService wechatDirectAppCapabilityService;
|
||||
private final WechatDirectAppAuthConfigService wechatDirectAppAuthConfigService;
|
||||
private final WechatDirectAppManager wechatDirectAppManager;
|
||||
private final PlatformUrlConfigService platformUrlConfigService;
|
||||
|
||||
@Override
|
||||
public ProductEnum getProduct() {
|
||||
return ProductEnum.WECHAT_PAY;
|
||||
}
|
||||
|
||||
/// 生成公众号 OAuth 授权链接
|
||||
///
|
||||
/// 拼接回调地址({paymentGatewayBaseUrl}/auth/wechat/{authToken}), 委托 capability-wechat 生成微信 OAuth URL。
|
||||
@Override
|
||||
public AuthUrlResult generateAuthUrl(GenerateAuthUrlParam param, String authToken) {
|
||||
WechatDirectApp app = resolveApp(param.getChannelMchNo(), param.getCapability(), param.getOpAppId());
|
||||
WechatDirectAppAuthConfig authConfig = wechatDirectAppAuthConfigService.findByWechatDirectAppId(app.getId());
|
||||
String redirectUri = buildRedirectUri(authToken);
|
||||
WechatAuthUrlResult result = wechatMpAuthService.generateAuthUrl(
|
||||
redirectUri, app.getWxAppId(), authConfig.getAppSecret());
|
||||
return new AuthUrlResult().setAuthUrl(result.getAuthUrl());
|
||||
}
|
||||
|
||||
/// 通过授权 code(公众号 OAuth 回调的 code)换取 openId
|
||||
///
|
||||
/// 应用上下文优先从 session(H5 会话码场景)恢复, 否则取 param(小程序直连场景)。
|
||||
@Override
|
||||
public AuthResult doAuth(AuthCodeParam param, AuthSession session) {
|
||||
String channelMchNo = session != null && StrUtil.isNotBlank(session.getChannelMchNo())
|
||||
? session.getChannelMchNo() : param.getChannelMchNo();
|
||||
String capability = session != null && StrUtil.isNotBlank(session.getCapability())
|
||||
? session.getCapability() : param.getCapability();
|
||||
String opAppId = session != null && StrUtil.isNotBlank(session.getOpAppId())
|
||||
? session.getOpAppId() : param.getOpAppId();
|
||||
WechatDirectApp app = resolveApp(channelMchNo, capability, opAppId);
|
||||
WechatDirectAppAuthConfig authConfig = wechatDirectAppAuthConfigService.findByWechatDirectAppId(app.getId());
|
||||
WechatAuthResult data = wechatMpAuthService.getTokenAndOpenId(
|
||||
param.getAuthCode(), app.getWxAppId(), authConfig.getAppSecret());
|
||||
if (StrUtil.isBlank(data.getOpenId())) {
|
||||
// 微信: 获取openId失败
|
||||
throw new BizInfoException(CommonErrorCode.SYSTEM_ERROR, "error.channel.wechat.authFailed", "openId is blank");
|
||||
}
|
||||
return new AuthResult()
|
||||
.setOpenId(data.getOpenId())
|
||||
.setAccessToken(data.getAccessToken());
|
||||
}
|
||||
|
||||
/// 解析认证应用: opAppId 显式指定(校验预配) > capability 自动解析
|
||||
private WechatDirectApp resolveApp(String channelMchNo, String capability, String opAppId) {
|
||||
if (StrUtil.isNotBlank(opAppId)) {
|
||||
// opAppId 必须在系统预配过(硬约束, 防任意 appId 滥用)
|
||||
return wechatDirectAppManager.findByChannelMchNoAndWxAppId(channelMchNo, opAppId)
|
||||
.orElseThrow(() -> new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR,
|
||||
"error.channel.wechat.opAppIdNotFound", opAppId));
|
||||
}
|
||||
return wechatDirectAppCapabilityService.resolveApp(channelMchNo, capability)
|
||||
// 微信: 直连商户应用不存在
|
||||
.orElseThrow(() -> new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR,
|
||||
"error.channel.wechat.mchAppNotFound"));
|
||||
}
|
||||
|
||||
/// 拼接认证回调地址: {paymentGatewayBaseUrl}/auth/wechat/{authToken}
|
||||
private String buildRedirectUri(String authToken) {
|
||||
String base = platformUrlConfigService.getUrlConfig().getPaymentGatewayBaseUrl();
|
||||
if (StrUtil.isBlank(base)) {
|
||||
// 支付网关前端地址未配置
|
||||
throw new BizInfoException(DaxPayErrorCode.CONFIG_ERROR, "error.common.gatewayUrlNotConfigured");
|
||||
}
|
||||
return StrUtil.removeSuffix(base, "/") + "/auth/wechat/" + authToken;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
package cn.daxpay.open.channel.wechat.strategy.isv;
|
||||
|
||||
import cn.daxpay.open.channel.wechat.code.WechatAuthAppTypeEnum;
|
||||
import cn.daxpay.open.channel.wechat.dao.isv.WechatIsvAppManager;
|
||||
import cn.daxpay.open.channel.wechat.dao.isv.WechatIsvChannelMerchantManager;
|
||||
import cn.daxpay.open.channel.wechat.dao.isv.WechatIsvMchAppManager;
|
||||
import cn.daxpay.open.channel.wechat.entity.isv.WechatIsvApp;
|
||||
import cn.daxpay.open.channel.wechat.entity.isv.WechatIsvAppAuthConfig;
|
||||
import cn.daxpay.open.channel.wechat.entity.isv.WechatIsvChannelMerchant;
|
||||
import cn.daxpay.open.channel.wechat.entity.isv.WechatIsvMchApp;
|
||||
import cn.daxpay.open.channel.wechat.entity.isv.WechatIsvMchAppAuthConfig;
|
||||
import cn.daxpay.open.channel.wechat.service.isv.WechatIsvAppAuthConfigService;
|
||||
import cn.daxpay.open.channel.wechat.service.isv.WechatIsvAppCapabilityService;
|
||||
import cn.daxpay.open.channel.wechat.service.isv.WechatIsvMchAppAuthConfigService;
|
||||
import cn.daxpay.open.channel.wechat.service.isv.WechatIsvMchAppCapabilityService;
|
||||
import cn.daxpay.open.payment.core.assist.AuthSession;
|
||||
import cn.daxpay.open.payment.core.strategy.auth.AbsChannelAuthStrategy;
|
||||
import cn.daxpay.open.payment.unipay.param.assist.AuthCodeParam;
|
||||
import cn.daxpay.open.payment.unipay.param.assist.GenerateAuthUrlParam;
|
||||
import cn.daxpay.open.payment.unipay.result.assist.AuthResult;
|
||||
import cn.daxpay.open.payment.unipay.result.assist.AuthUrlResult;
|
||||
import cn.daxpay.open.platform.capability.wechat.auth.result.WechatAuthResult;
|
||||
import cn.daxpay.open.platform.capability.wechat.auth.result.WechatAuthUrlResult;
|
||||
import cn.daxpay.open.platform.capability.wechat.auth.service.WechatMpAuthService;
|
||||
import cn.daxpay.open.platform.core.code.CommonErrorCode;
|
||||
import cn.daxpay.open.platform.core.code.DaxPayErrorCode;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import cn.daxpay.open.platform.core.exception.BizInfoException;
|
||||
import cn.daxpay.open.platform.system.service.config.PlatformUrlConfigService;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/// # 微信服务商认证策略
|
||||
///
|
||||
/// 微信服务商模式(WECHAT_ISV)下获取用户标识(openId)。按特约商户配置的认证应用类型
|
||||
/// ([cn.daxpay.open.channel.wechat.entity.isv.WechatIsvChannelMerchant.authAppType]) 路由:
|
||||
///
|
||||
/// - **SP_APP(默认)**: 用服务商应用(WechatIsvApp.sp_appid) + WechatIsvAppAuthConfig 认证, 所得为 sp 维度 openId
|
||||
/// - **SUB_APP**: 用子商户应用(WechatIsvMchApp.sub_appid) + WechatIsvMchAppAuthConfig 认证, 所得为 sub 维度 openId
|
||||
///
|
||||
/// ## appId 解析优先级
|
||||
/// 1. opAppId 显式指定 → 按 authAppType 查对应表校验预配, 命中即用
|
||||
/// 2. 否则按 authAppType + capability 自动解析
|
||||
///
|
||||
/// 微信 OAuth 调用 capability-wechat, 与支付通道子应用解耦; 区别仅是主应用传入的 wxAppId/appSecret 来源不同。
|
||||
@Slf4j
|
||||
@Service
|
||||
@RequiredArgsConstructor
|
||||
public class WechatIsvAuthStrategy extends AbsChannelAuthStrategy {
|
||||
|
||||
private final WechatMpAuthService wechatMpAuthService;
|
||||
private final WechatIsvAppCapabilityService wechatIsvAppCapabilityService;
|
||||
private final WechatIsvAppAuthConfigService wechatIsvAppAuthConfigService;
|
||||
private final WechatIsvAppManager wechatIsvAppManager;
|
||||
private final WechatIsvMchAppCapabilityService wechatIsvMchAppCapabilityService;
|
||||
private final WechatIsvMchAppAuthConfigService wechatIsvMchAppAuthConfigService;
|
||||
private final WechatIsvMchAppManager wechatIsvMchAppManager;
|
||||
private final WechatIsvChannelMerchantManager wechatIsvChannelMerchantManager;
|
||||
private final PlatformUrlConfigService platformUrlConfigService;
|
||||
|
||||
@Override
|
||||
public ProductEnum getProduct() {
|
||||
return ProductEnum.WECHAT_ISV;
|
||||
}
|
||||
|
||||
/// 生成公众号 OAuth 授权链接
|
||||
@Override
|
||||
public AuthUrlResult generateAuthUrl(GenerateAuthUrlParam param, String authToken) {
|
||||
ResolvedAuthApp app = resolveAuthApp(param.getChannelMchNo(), param.getCapability(), param.getOpAppId());
|
||||
String redirectUri = buildRedirectUri(authToken);
|
||||
WechatAuthUrlResult result = wechatMpAuthService.generateAuthUrl(
|
||||
redirectUri, app.wxAppId(), app.appSecret());
|
||||
return new AuthUrlResult().setAuthUrl(result.getAuthUrl());
|
||||
}
|
||||
|
||||
/// 通过授权 code 换取 openId
|
||||
@Override
|
||||
public AuthResult doAuth(AuthCodeParam param, AuthSession session) {
|
||||
String channelMchNo = session != null && StrUtil.isNotBlank(session.getChannelMchNo())
|
||||
? session.getChannelMchNo() : param.getChannelMchNo();
|
||||
String capability = session != null && StrUtil.isNotBlank(session.getCapability())
|
||||
? session.getCapability() : param.getCapability();
|
||||
String opAppId = session != null && StrUtil.isNotBlank(session.getOpAppId())
|
||||
? session.getOpAppId() : param.getOpAppId();
|
||||
ResolvedAuthApp app = resolveAuthApp(channelMchNo, capability, opAppId);
|
||||
WechatAuthResult data = wechatMpAuthService.getTokenAndOpenId(
|
||||
param.getAuthCode(), app.wxAppId(), app.appSecret());
|
||||
if (StrUtil.isBlank(data.getOpenId())) {
|
||||
// 微信: 获取openId失败
|
||||
throw new BizInfoException(CommonErrorCode.SYSTEM_ERROR, "error.channel.wechat.authFailed", "openId is blank");
|
||||
}
|
||||
return new AuthResult()
|
||||
.setOpenId(data.getOpenId())
|
||||
.setAccessToken(data.getAccessToken());
|
||||
}
|
||||
|
||||
/// 解析认证应用(返回 wxAppId + appSecret)
|
||||
///
|
||||
/// 优先级: opAppId(按authAppType校验对应表) > authAppType + capability 自动解析
|
||||
private ResolvedAuthApp resolveAuthApp(String channelMchNo, String capability, String opAppId) {
|
||||
WechatAuthAppTypeEnum authAppType = loadAuthAppType(channelMchNo);
|
||||
if (StrUtil.isNotBlank(opAppId)) {
|
||||
return resolveByOpAppId(channelMchNo, opAppId, authAppType);
|
||||
}
|
||||
return resolveByConfig(channelMchNo, capability, authAppType);
|
||||
}
|
||||
|
||||
/// 读取特约商户的认证应用类型, 默认 SP_APP(服务商应用)
|
||||
private WechatAuthAppTypeEnum loadAuthAppType(String channelMchNo) {
|
||||
return wechatIsvChannelMerchantManager.findByChannelMchNo(channelMchNo)
|
||||
.map(WechatIsvChannelMerchant::getAuthAppType)
|
||||
.filter(StrUtil::isNotBlank)
|
||||
.map(WechatAuthAppTypeEnum::valueOf)
|
||||
.orElse(WechatAuthAppTypeEnum.SP_APP);
|
||||
}
|
||||
|
||||
/// 按配置(authAppType + capability)解析应用
|
||||
private ResolvedAuthApp resolveByConfig(String channelMchNo, String capability, WechatAuthAppTypeEnum authAppType) {
|
||||
if (authAppType == WechatAuthAppTypeEnum.SP_APP) {
|
||||
WechatIsvApp app = wechatIsvAppCapabilityService.resolveApp(capability)
|
||||
// 微信: 服务商应用不存在
|
||||
.orElseThrow(() -> new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR,
|
||||
"error.channel.wechat.appNotFound"));
|
||||
WechatIsvAppAuthConfig cfg = wechatIsvAppAuthConfigService.findByWechatIsvAppId(app.getId());
|
||||
return new ResolvedAuthApp(app.getWxAppId(), cfg.getAppSecret());
|
||||
}
|
||||
// SUB_APP: 子商户应用(仅显式配置, 未配置返回empty)
|
||||
WechatIsvMchApp app = wechatIsvMchAppCapabilityService.resolveApp(channelMchNo, capability)
|
||||
// 微信: 服务商通道商户应用不存在
|
||||
.orElseThrow(() -> new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR,
|
||||
"error.channel.wechat.mchAppNotFound"));
|
||||
WechatIsvMchAppAuthConfig cfg = wechatIsvMchAppAuthConfigService.findByWechatIsvMchAppId(app.getId());
|
||||
return new ResolvedAuthApp(app.getWxAppId(), cfg.getAppSecret());
|
||||
}
|
||||
|
||||
/// 按 opAppId 解析应用(按 authAppType 查对应表校验预配)
|
||||
private ResolvedAuthApp resolveByOpAppId(String channelMchNo, String opAppId, WechatAuthAppTypeEnum authAppType) {
|
||||
if (authAppType == WechatAuthAppTypeEnum.SP_APP) {
|
||||
WechatIsvApp app = wechatIsvAppManager.findByWxAppId(opAppId)
|
||||
.orElseThrow(() -> new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR,
|
||||
"error.channel.wechat.opAppIdNotFound", opAppId));
|
||||
WechatIsvAppAuthConfig cfg = wechatIsvAppAuthConfigService.findByWechatIsvAppId(app.getId());
|
||||
return new ResolvedAuthApp(app.getWxAppId(), cfg.getAppSecret());
|
||||
}
|
||||
WechatIsvMchApp app = wechatIsvMchAppManager.findByChannelMchNoAndWxAppId(channelMchNo, opAppId)
|
||||
.orElseThrow(() -> new BizInfoException(CommonErrorCode.VALIDATE_PARAMETERS_ERROR,
|
||||
"error.channel.wechat.opAppIdNotFound", opAppId));
|
||||
WechatIsvMchAppAuthConfig cfg = wechatIsvMchAppAuthConfigService.findByWechatIsvMchAppId(app.getId());
|
||||
return new ResolvedAuthApp(app.getWxAppId(), cfg.getAppSecret());
|
||||
}
|
||||
|
||||
/// 拼接认证回调地址: {paymentGatewayBaseUrl}/auth/wechat/{authToken}
|
||||
private String buildRedirectUri(String authToken) {
|
||||
String base = platformUrlConfigService.getUrlConfig().getPaymentGatewayBaseUrl();
|
||||
if (StrUtil.isBlank(base)) {
|
||||
// 支付网关前端地址未配置
|
||||
throw new BizInfoException(DaxPayErrorCode.CONFIG_ERROR, "error.common.gatewayUrlNotConfigured");
|
||||
}
|
||||
return StrUtil.removeSuffix(base, "/") + "/auth/wechat/" + authToken;
|
||||
}
|
||||
|
||||
/// 解析后的认证应用(wxAppId + appSecret)
|
||||
private record ResolvedAuthApp(String wxAppId, String appSecret) { }
|
||||
}
|
||||
Reference in New Issue
Block a user