mirror of
https://gitee.com/dromara/dax-pay
synced 2026-08-12 23:45:39 +08:00
refactor(auth): 认证参数 capability → method 改名 + 默认推导
认证链路中 capability 与 PayMethodEnum code 同构, 改名为 method 更直观。 内部应用解析层(WxAppFacade/WxAppResolveService)保留 capability 不动。 新增 resolveDefaultMethod: method 缺失时按 authType 补默认值 (wechat 补 wechat_jsapi, douyin 补 douyin_h5), 解决 OPEN/调试/签名API 等入口未传 method 导致应用定位失败的问题。
This commit is contained in:
@@ -47,7 +47,7 @@ public class DouyinDirectAuthStrategy extends AbsProductAuthStrategy {
|
||||
@Override
|
||||
public AuthUrlResult generateAuthUrl(GenerateAuthUrlParam param, String authToken) {
|
||||
DouyinDirectApp app = douyinDirectAppCapabilityService.resolveWebAppForH5Auth(
|
||||
param.getChannelMchNo(), param.getCapability(), param.getChannelAppId());
|
||||
param.getChannelMchNo(), param.getMethod(), param.getChannelAppId());
|
||||
DouyinDirectAppAuthConfig authConfig = douyinDirectAppAuthConfigService.findByDouyinDirectAppIdForAuth(app.getId());
|
||||
if (StrUtil.isBlank(authConfig.getAppSecret())) {
|
||||
// 抖音: 直连应用授权密钥未配置
|
||||
@@ -64,7 +64,7 @@ public class DouyinDirectAuthStrategy extends AbsProductAuthStrategy {
|
||||
public AuthResult doAuth(AuthCodeParam param, AuthSession session) {
|
||||
var ctx = resolveContext(param, session);
|
||||
DouyinDirectApp app = douyinDirectAppCapabilityService.resolveWebAppForH5Auth(
|
||||
ctx.channelMchNo(), ctx.capability(), ctx.channelAppId());
|
||||
ctx.channelMchNo(), ctx.method(), ctx.channelAppId());
|
||||
DouyinDirectAppAuthConfig authConfig = douyinDirectAppAuthConfigService.findByDouyinDirectAppIdForAuth(app.getId());
|
||||
if (StrUtil.isBlank(authConfig.getAppSecret())) {
|
||||
// 抖音: 直连应用授权密钥未配置
|
||||
|
||||
@@ -52,7 +52,7 @@ public class WechatDirectAuthStrategy extends AbsProductAuthStrategy {
|
||||
@Override
|
||||
public AuthUrlResult generateAuthUrl(GenerateAuthUrlParam param, String authToken) {
|
||||
WxAppView app = resolveApp(param.getMchNo(), param.getChannelMchNo(),
|
||||
param.getCapability(), param.getChannelAppId());
|
||||
param.getMethod(), param.getChannelAppId());
|
||||
String redirectUri = AuthRedirectUri.WECHAT.buildRedirectUri(platformUrlConfigService);
|
||||
WechatAuthUrlResult result = wechatMpAuthService.generateAuthUrl(
|
||||
redirectUri, app.wxAppId(), app.appSecret(), authToken);
|
||||
@@ -65,7 +65,7 @@ public class WechatDirectAuthStrategy extends AbsProductAuthStrategy {
|
||||
@Override
|
||||
public AuthResult doAuth(AuthCodeParam param, AuthSession session) {
|
||||
var ctx = resolveContext(param, session);
|
||||
WxAppView app = resolveApp(param.getMchNo(), ctx.channelMchNo(), ctx.capability(), ctx.channelAppId());
|
||||
WxAppView app = resolveApp(param.getMchNo(), ctx.channelMchNo(), ctx.method(), ctx.channelAppId());
|
||||
WechatAuthResult data = wechatMpAuthService.getTokenAndOpenId(
|
||||
param.getAuthCode(), app.wxAppId(), app.appSecret());
|
||||
if (StrUtil.isBlank(data.getOpenId())) {
|
||||
|
||||
@@ -57,7 +57,7 @@ public class WechatIsvAuthStrategy extends AbsProductAuthStrategy {
|
||||
@Override
|
||||
public AuthUrlResult generateAuthUrl(GenerateAuthUrlParam param, String authToken) {
|
||||
ResolvedAuthApp app = resolveAuthApp(param.getMchNo(), param.getChannelMchNo(),
|
||||
param.getCapability(), param.getChannelAppId());
|
||||
param.getMethod(), param.getChannelAppId());
|
||||
String redirectUri = AuthRedirectUri.WECHAT.buildRedirectUri(platformUrlConfigService);
|
||||
WechatAuthUrlResult result = wechatMpAuthService.generateAuthUrl(
|
||||
redirectUri, app.wxAppId(), app.appSecret(), authToken);
|
||||
@@ -68,7 +68,7 @@ public class WechatIsvAuthStrategy extends AbsProductAuthStrategy {
|
||||
@Override
|
||||
public AuthResult doAuth(AuthCodeParam param, AuthSession session) {
|
||||
var ctx = resolveContext(param, session);
|
||||
ResolvedAuthApp app = resolveAuthApp(param.getMchNo(), ctx.channelMchNo(), ctx.capability(), ctx.channelAppId());
|
||||
ResolvedAuthApp app = resolveAuthApp(param.getMchNo(), ctx.channelMchNo(), ctx.method(), ctx.channelAppId());
|
||||
WechatAuthResult data = wechatMpAuthService.getTokenAndOpenId(
|
||||
param.getAuthCode(), app.wxAppId(), app.appSecret());
|
||||
if (StrUtil.isBlank(data.getOpenId())) {
|
||||
|
||||
@@ -53,9 +53,9 @@ public class AuthSession {
|
||||
/// 通道商户号
|
||||
private String channelMchNo;
|
||||
|
||||
/// 支付能力编码(用于解析具体应用)
|
||||
/// @see cn.daxpay.open.platform.core.enums.pay.channel.PayCapabilityEnum
|
||||
private String capability;
|
||||
/// 支付方式编码(用于解析具体应用)
|
||||
/// @see cn.daxpay.open.platform.core.enums.pay.channel.PayMethodEnum
|
||||
private String method;
|
||||
|
||||
/// 指定认证应用AppId(可选, 优先级高于配置自动解析)
|
||||
private String channelAppId;
|
||||
|
||||
@@ -23,22 +23,22 @@ public abstract class AbsProductAuthStrategy implements PaymentStrategy {
|
||||
/// 通过AuthCode获取认证结果
|
||||
///
|
||||
/// @param session 认证会话上下文(H5场景从 authToken 恢复; 小程序直连场景可为空, 此时从 param 取上下文)。
|
||||
/// 策略需兼容 session 为 null 的情况(优先用 param 的 channelMchNo/capability/channelAppId)。
|
||||
/// 策略需兼容 session 为 null 的情况(优先用 param 的 channelMchNo/method/channelAppId)。
|
||||
public abstract AuthResult doAuth(AuthCodeParam param, AuthSession session);
|
||||
|
||||
/// 解析认证上下文: session 字段优先, param 兜底
|
||||
///
|
||||
/// H5 OAuth 重定向场景从 session 恢复(param 仅含 authToken);
|
||||
/// 小程序直连场景 session 为空, 从 param 取上下文。
|
||||
/// 返回 [ProductAuthContext](channelMchNo / capability / channelAppId)。
|
||||
/// 返回 [ProductAuthContext](channelMchNo / method / channelAppId)。
|
||||
protected ProductAuthContext resolveContext(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 method = session != null && StrUtil.isNotBlank(session.getMethod())
|
||||
? session.getMethod() : param.getMethod();
|
||||
String channelAppId = session != null && StrUtil.isNotBlank(session.getChannelAppId())
|
||||
? session.getChannelAppId() : param.getChannelAppId();
|
||||
return new ProductAuthContext(channelMchNo, capability, channelAppId);
|
||||
return new ProductAuthContext(channelMchNo, method, channelAppId);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ package cn.daxpay.open.payment.auth.merchant;
|
||||
///
|
||||
/// ## 字段含义
|
||||
/// - `channelMchNo`: 通道商户号(定位特约商户主数据 / 反查 mchNo)
|
||||
/// - `capability`: 支付能力编码(公众号 / 小程序, 决定应用维度与 openId 类型)
|
||||
/// - `method`: 支付方式编码(公众号 / 小程序, 决定应用维度与 openId 类型)
|
||||
/// - `channelAppId`: 显式指定的应用 AppId(可选, 优先级高于配置自动解析)
|
||||
public record ProductAuthContext(String channelMchNo, String capability, String channelAppId) {
|
||||
public record ProductAuthContext(String channelMchNo, String method, String channelAppId) {
|
||||
}
|
||||
|
||||
@@ -13,7 +13,9 @@ import cn.daxpay.open.payment.unipay.result.assist.AuthResult;
|
||||
import cn.daxpay.open.payment.unipay.result.assist.AuthUrlResult;
|
||||
import cn.daxpay.open.platform.core.code.CommonErrorCode;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.ProductEnum;
|
||||
import cn.daxpay.open.platform.core.enums.pay.channel.PayMethodEnum;
|
||||
import cn.daxpay.open.platform.core.enums.unipay.ChannelAuthStatusEnum;
|
||||
import cn.daxpay.open.platform.core.enums.unipay.ChannelAuthTypeEnum;
|
||||
import cn.daxpay.open.platform.core.exception.BizInfoException;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
@@ -47,6 +49,8 @@ public class ProductAuthService {
|
||||
/// 不含 queryCode, 需随会话保存)。
|
||||
public AuthUrlResult generateAuthUrl(GenerateAuthUrlParam param) {
|
||||
initMchContext(param.getAppId(), param.getMchNo(), null);
|
||||
// 支付方式缺失时按认证类型推导默认值(OAuth 重定向天然只适用于公众号场景)
|
||||
param.setMethod(resolveDefaultMethod(param.getAuthType(), param.getMethod()));
|
||||
// 支付产品: 显式传入优先, 否则从通道商户号反查(调试工具/直接指定通道商户场景)
|
||||
String product = resolveProduct(param);
|
||||
assertNotAlipayProduct(product);
|
||||
@@ -58,7 +62,7 @@ public class ProductAuthService {
|
||||
AuthSession session = new AuthSession()
|
||||
.setProduct(product)
|
||||
.setChannelMchNo(param.getChannelMchNo())
|
||||
.setCapability(param.getCapability())
|
||||
.setMethod(param.getMethod())
|
||||
.setChannelAppId(param.getChannelAppId())
|
||||
.setReturnPath(param.getReturnPath())
|
||||
.setQueryCode(queryCode)
|
||||
@@ -78,6 +82,8 @@ public class ProductAuthService {
|
||||
/// 由认证分发层在调用前通过 [AuthSessionStore#loadSession] 加载后注入。
|
||||
public AuthResult auth(AuthCodeParam param, AuthSession session) {
|
||||
initMchContext(param.getAppId(), param.getMchNo(), session);
|
||||
// 支付方式缺失时按认证类型推导(session 恢复场景已有 method, 小程序直连场景需补)
|
||||
param.setMethod(resolveDefaultMethod(param.getAuthType(), param.getMethod()));
|
||||
// product 优先从会话恢复, 其次取参数(小程序直连场景)
|
||||
String product = (session != null && StrUtil.isNotBlank(session.getProduct()))
|
||||
? session.getProduct() : param.getProduct();
|
||||
@@ -136,4 +142,21 @@ public class ProductAuthService {
|
||||
throw new IllegalStateException("支付宝认证应走平台级 Provider, 不应进入产品策略: " + product);
|
||||
}
|
||||
}
|
||||
|
||||
/// 支付方式缺失时按认证类型推导默认值
|
||||
///
|
||||
/// OAuth 重定向认证天然只适用于公众号(H5网页授权)场景, 微信默认补 jsapi, 抖音默认补 h5。
|
||||
/// 已显式传入 method 的场景(网关/码牌)不受影响。
|
||||
private static String resolveDefaultMethod(String authType, String method) {
|
||||
if (StrUtil.isNotBlank(method)) {
|
||||
return method;
|
||||
}
|
||||
if (ChannelAuthTypeEnum.WECHAT.getCode().equals(authType)) {
|
||||
return PayMethodEnum.WECHAT_JSAPI.getCode();
|
||||
}
|
||||
if (ChannelAuthTypeEnum.DOUYIN.getCode().equals(authType)) {
|
||||
return PayMethodEnum.DOUYIN_H5.getCode();
|
||||
}
|
||||
return method;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,7 +85,7 @@ public class GatewayAuthService {
|
||||
RouteSnapshot route = resolveRoute(order, param);
|
||||
authParam.setProduct(route.product());
|
||||
authParam.setChannelMchNo(route.channelMchNo());
|
||||
authParam.setCapability(route.capability());
|
||||
authParam.setMethod(route.method());
|
||||
authParam.setChannelAppId(route.channelAppId());
|
||||
}
|
||||
return channelAuthService.generateAuthUrl(authParam);
|
||||
@@ -261,6 +261,6 @@ public class GatewayAuthService {
|
||||
}
|
||||
|
||||
/// 路由快照(供组装 GenerateAuthUrlParam)
|
||||
private record RouteSnapshot(String product, String channelMchNo, String capability, String channelAppId) {
|
||||
private record RouteSnapshot(String product, String channelMchNo, String method, String channelAppId) {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,11 +52,11 @@ public class AuthCodeParam extends MerchantPaymentCommonParam {
|
||||
@Schema(description = "支付产品编码")
|
||||
private String product;
|
||||
|
||||
/// 支付能力编码, 用于解析具体应用, 小程序场景需要; 会话码场景从会话恢复
|
||||
/// @see cn.daxpay.open.platform.core.enums.pay.channel.PayCapabilityEnum
|
||||
@Size(max = 32, message = "{validation.field.capability.size}")
|
||||
@Schema(description = "支付能力编码")
|
||||
private String capability;
|
||||
/// 支付方式编码, 用于解析具体应用, 小程序场景需要; 会话码场景从会话恢复
|
||||
/// @see cn.daxpay.open.platform.core.enums.pay.channel.PayMethodEnum
|
||||
@Size(max = 32, message = "{validation.field.method.size}")
|
||||
@Schema(description = "支付方式编码")
|
||||
private String method;
|
||||
|
||||
/// 指定认证使用的应用AppId, 会话码恢复上下文时可不传, 优先级高于配置自动解析
|
||||
@Size(max = 128, message = "{validation.field.channelAppId.size}")
|
||||
|
||||
@@ -38,10 +38,10 @@ public class GenerateAuthUrlParam extends MerchantPaymentCommonParam {
|
||||
@Schema(description = "来源回跳路径")
|
||||
private String returnPath;
|
||||
|
||||
/// 支付能力编码, 用于解析具体应用(公众号/小程序), 不同能力对应不同应用维度的openId
|
||||
/// @see cn.daxpay.open.platform.core.enums.pay.channel.PayCapabilityEnum
|
||||
@Size(max = 32, message = "{validation.field.capability.size}")
|
||||
@Schema(description = "支付能力编码")
|
||||
private String capability;
|
||||
/// 支付方式编码, 决定解析哪个应用(公众号/小程序等), 不同方式对应不同应用维度的 openId
|
||||
/// @see cn.daxpay.open.platform.core.enums.pay.channel.PayMethodEnum
|
||||
@Size(max = 32, message = "{validation.field.method.size}")
|
||||
@Schema(description = "支付方式编码")
|
||||
private String method;
|
||||
}
|
||||
|
||||
|
||||
@@ -182,7 +182,7 @@ public class CodePayAssistService {
|
||||
authParam.setAppId(mchApp.getAppId());
|
||||
authParam.setProduct(routeParam.getProduct());
|
||||
authParam.setChannelMchNo(routeParam.getChannelMchNo());
|
||||
authParam.setCapability(routeParam.getCapability());
|
||||
authParam.setMethod(routeParam.getCapability());
|
||||
authParam.setReturnPath(returnPath);
|
||||
authParam.setAuthType(this.mapAuthType(clientEnv));
|
||||
return channelAuthService.generateAuthUrl(authParam);
|
||||
|
||||
Reference in New Issue
Block a user