mirror of
https://gitee.com/dromara/dax-pay
synced 2026-08-10 06:46:04 +08:00
refactor(social): 支付宝登录并入统一 Social 认证入口
用 AlipaySocialAuthRequest 收口非标准 OAuth,删除独立 /social/alipay 端点, 登录与绑定与标准平台共用 SocialEndpoint 编排。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -35,8 +35,8 @@ public class SocialAuthRequestFactory {
|
||||
case FEISHU -> new FeishuRequest(config);
|
||||
case DINGTALK -> new DingTalkRequest(config);
|
||||
case DOUYIN -> new DouyinRequest(config);
|
||||
// 支付宝非标准 OAuth2, 不走 JustAuth 工厂, 由 iam 模块 AlipayAuthEndpoint 独立处理
|
||||
case ALIPAY -> throw new OperationFailException("error.social.alipayUseDedicatedEndpoint");
|
||||
// 支付宝由 iam 模块 AlipaySocialAuthRequestFactory 创建, 不走本工厂
|
||||
case ALIPAY -> throw new OperationFailException("error.social.unsupportedSource");
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -48,10 +48,8 @@ public enum SocialSourceEnum implements I18nSupport {
|
||||
"https://api.dingtalk.com/v1.0/contact/users/me"
|
||||
),
|
||||
|
||||
/// 支付宝(非标准 OAuth2, 不走 JustAuth 流程)
|
||||
/// 端点地址留空, 实际授权由 iam 模块的 AlipayAuthEndpoint 独立处理(调用 alipay.system.oauth.token)。
|
||||
/// 在 [SocialAuthRequestFactory] 中会对该 source 抛出"请使用支付宝专用端点"异常,
|
||||
/// 避免误走标准 OAuth2 工厂分支。
|
||||
/// 支付宝(非标准 OAuth2: alipay.system.oauth.token)
|
||||
/// 端点地址留空; 授权由 iam 模块 [AlipaySocialAuthRequest] 实现, 经统一 SocialEndpoint 入口编排。
|
||||
/// 排序位于钉钉之后、抖音之前。
|
||||
ALIPAY("alipay", "", "", ""),
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
"configDuplicated": "The platform configuration already exists",
|
||||
"notConfigured": "The platform is not configured and cannot be toggled",
|
||||
"authCodeBlank": "Authorization code cannot be empty",
|
||||
"alipayUseDedicatedEndpoint": "Alipay uses non-standard OAuth2, please use the dedicated endpoint /social/alipay/render",
|
||||
"alipayNotConfigured": "Platform-level Alipay configuration is incomplete, please configure it in 'Third-party Platform Management' first",
|
||||
"weCom": {
|
||||
"notCorpMember": "Not a member of this enterprise, login is not supported"
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
"configDuplicated": "该平台配置已存在",
|
||||
"notConfigured": "平台尚未配置,无法启停",
|
||||
"authCodeBlank": "授权码不能为空",
|
||||
"alipayUseDedicatedEndpoint": "支付宝非标准 OAuth2,请使用专用授权端点 /social/alipay/render",
|
||||
"alipayNotConfigured": "平台级支付宝配置不完整,请先在「三方平台管理」中配置",
|
||||
"weCom": {
|
||||
"notCorpMember": "非本企业成员,不支持登录"
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
<artifactId>capability-social</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<!-- 支付宝开放平台能力(AlipayAuthEndpoint 授权登录使用) -->
|
||||
<!-- 支付宝开放平台能力(AlipaySocialAuthRequest 授权登录使用) -->
|
||||
<dependency>
|
||||
<groupId>cn.daxpay.open</groupId>
|
||||
<artifactId>capability-alipay</artifactId>
|
||||
|
||||
@@ -1,177 +0,0 @@
|
||||
package cn.daxpay.open.platform.iam.endpoint;
|
||||
|
||||
import cn.daxpay.open.platform.capability.alipay.auth.config.AlipayAuthConfig;
|
||||
import cn.daxpay.open.platform.capability.alipay.auth.result.AlipayAuthResult;
|
||||
import cn.daxpay.open.platform.capability.alipay.auth.service.AlipayAuthCapability;
|
||||
import cn.daxpay.open.platform.capability.auth.util.SecurityUtil;
|
||||
import cn.daxpay.open.platform.capability.social.justauth.SocialSourceEnum;
|
||||
import cn.daxpay.open.platform.capability.social.justauth.model.AuthUser;
|
||||
import cn.daxpay.open.platform.core.annotation.IgnoreAuth;
|
||||
import cn.daxpay.open.platform.core.rest.Res;
|
||||
import cn.daxpay.open.platform.core.rest.result.Result;
|
||||
import cn.daxpay.open.platform.core.exception.operation.OperationFailException;
|
||||
import cn.daxpay.open.platform.iam.enums.SocialAuthMode;
|
||||
import cn.daxpay.open.platform.iam.enums.SocialClientEnum;
|
||||
import cn.daxpay.open.platform.iam.result.social.SocialExchangeResult;
|
||||
import cn.daxpay.open.platform.iam.entity.social.SocialLoginConfig;
|
||||
import cn.daxpay.open.platform.iam.service.social.IamSocialLoginHandler;
|
||||
import cn.daxpay.open.platform.iam.service.social.IamUserSocialBindStore;
|
||||
import cn.daxpay.open.platform.iam.service.social.SocialLoginConfigService;
|
||||
import cn.daxpay.open.platform.system.entity.config.platform.PlatformUrlConfig;
|
||||
import cn.daxpay.open.platform.system.service.config.PlatformAlipayAuthConfigService;
|
||||
import cn.daxpay.open.platform.system.service.config.PlatformUrlConfigService;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/// # 支付宝授权登录端点
|
||||
///
|
||||
/// 支付宝非标准 OAuth2(走 `alipay.system.oauth.token`), 不复用 JustAuth 的 [SocialEndpoint],
|
||||
/// 独立实现 render/exchange。但登录态签发、绑定关系存储复用 iam 现有体系
|
||||
/// ([IamSocialLoginHandler] / [IamUserSocialBindStore]), 绑定写入 `iam_user_social` 表(source=`alipay`)。
|
||||
///
|
||||
/// ## 流程
|
||||
/// 1. 前端调 `render` 获取授权链接(用平台级支付宝配置拼 `publicAppAuthorize.htm`)
|
||||
/// 2. 前端 `location.href` 跳转, 用户在支付宝授权
|
||||
/// 3. 支付宝回调到前端 `/auth/oauth-callback/alipay?auth_code=xxx&state=xxx`
|
||||
/// 4. 前端调 `exchange` 用 auth_code 换 userId, 完成登录或绑定
|
||||
///
|
||||
@Slf4j
|
||||
@IgnoreAuth
|
||||
@Tag(name = "支付宝授权登录")
|
||||
@RestController
|
||||
@RequestMapping("/social/alipay")
|
||||
@RequiredArgsConstructor
|
||||
public class AlipayAuthEndpoint {
|
||||
|
||||
/// 支付宝在三方登录体系中的 source 编码
|
||||
private static final String SOURCE = SocialSourceEnum.ALIPAY.getCode();
|
||||
|
||||
/// 授权范围: auth_user(需用户确认, 可获取用户信息)
|
||||
private static final String SCOPE = "auth_user";
|
||||
|
||||
/// 登录回调路径(前端路由, 与标准 OAuth2 平台同构: /auth/oauth-callback/{source})
|
||||
private static final String LOGIN_CALLBACK_PATH = "/auth/oauth-callback/" + SOURCE;
|
||||
|
||||
/// 绑定回调路径(前端路由: /auth/social-bind-callback/{source})
|
||||
private static final String BIND_CALLBACK_PATH = "/auth/social-bind-callback/" + SOURCE;
|
||||
|
||||
private final PlatformAlipayAuthConfigService platformAlipayAuthConfigService;
|
||||
private final AlipayAuthCapability alipayAuthCapability;
|
||||
private final PlatformUrlConfigService platformUrlConfigService;
|
||||
private final SocialLoginConfigService socialLoginConfigService;
|
||||
private final IamUserSocialBindStore socialBindStore;
|
||||
private final IamSocialLoginHandler socialLoginHandler;
|
||||
|
||||
/// 生成支付宝授权地址
|
||||
/// @param client 终端编码(admin/merchant), 用于解析端点配置中的 baseUrl
|
||||
/// @param mode 授权场景(不传则按登录态判断: 已登录=绑定, 未登录=登录)
|
||||
@GetMapping("/render")
|
||||
public Result<String> render(@RequestParam String client,
|
||||
@RequestParam(required = false) String mode) {
|
||||
// 0. 校验登录配置已启用(与标准 OAuth 平台一致)
|
||||
this.requireLoginEnabled();
|
||||
// 1. 读平台级配置
|
||||
AlipayAuthConfig capabilityConfig = platformAlipayAuthConfigService.toCapabilityConfig();
|
||||
if (!alipayAuthCapability.isConfigured(capabilityConfig)) {
|
||||
// 支付宝: 平台级支付宝配置不完整, 请先在「三方平台管理」中配置
|
||||
throw new OperationFailException("error.social.alipayNotConfigured");
|
||||
}
|
||||
// 2. 按 client 解析前端 baseUrl
|
||||
PlatformUrlConfig urlConfig = platformUrlConfigService.getUrlConfig();
|
||||
String baseUrl = SocialClientEnum.of(client).resolveBaseUrl(urlConfig);
|
||||
if (StrUtil.isBlank(baseUrl)) {
|
||||
// 社交登录: 端点配置缺失
|
||||
throw new OperationFailException("error.social.endpointNotConfigured");
|
||||
}
|
||||
// 3. 拼回调地址(LOGIN/BIND 不同路径)
|
||||
SocialAuthMode authMode = this.resolveMode(mode);
|
||||
String callbackPath = authMode == SocialAuthMode.BIND ? BIND_CALLBACK_PATH : LOGIN_CALLBACK_PATH;
|
||||
String redirectUri = baseUrl + callbackPath;
|
||||
// 4. 生成 state(OAuth2 合规, CSRF 防护)
|
||||
String state = IdUtil.fastSimpleUUID();
|
||||
// 5. 拼授权链接(平台级配置固定生产环境, 不再读取 sandbox)
|
||||
String authUrl = alipayAuthCapability.generateAuthUrl(capabilityConfig, redirectUri, SCOPE, state, false);
|
||||
return Res.ok(authUrl);
|
||||
}
|
||||
|
||||
/// 支付宝授权码兑换(LOGIN/BIND 由 mode 决定, 未传按登录态判断)
|
||||
/// @param authCode 支付宝回调回传的 auth_code
|
||||
/// @param state render 阶段生成的 state(原样回传, 目前仅做日志, 不做强校验)
|
||||
/// @param client 终端编码
|
||||
/// @param mode 授权场景
|
||||
@PostMapping("/exchange")
|
||||
public Result<SocialExchangeResult> exchange(@RequestParam("authCode") String authCode,
|
||||
@RequestParam("state") String state,
|
||||
@RequestParam("client") String client,
|
||||
@RequestParam(name = "mode", required = false) String mode,
|
||||
HttpServletRequest request,
|
||||
HttpServletResponse response) {
|
||||
try {
|
||||
// 0. 校验登录配置已启用
|
||||
this.requireLoginEnabled();
|
||||
// 1. 换 userId
|
||||
AlipayAuthConfig capabilityConfig = platformAlipayAuthConfigService.toCapabilityConfig();
|
||||
AlipayAuthResult authResult = alipayAuthCapability.getUserId(capabilityConfig, authCode);
|
||||
String alipayUserId = authResult.getUserId();
|
||||
if (StrUtil.isBlank(alipayUserId)) {
|
||||
return Res.ok(new SocialExchangeResult().setError("oauth_failed"));
|
||||
}
|
||||
// 2. 构造 AuthUser(复用现有绑定存储, source=alipay, uuid=支付宝userId)
|
||||
AuthUser authUser = new AuthUser()
|
||||
.setSource(SOURCE)
|
||||
.setUuid(alipayUserId)
|
||||
.setNickname("支付宝用户");
|
||||
// 3. 按场景分流
|
||||
SocialAuthMode authMode = this.resolveMode(mode);
|
||||
if (authMode == SocialAuthMode.BIND) {
|
||||
// 绑定场景: 必须已登录
|
||||
Long userId = SecurityUtil.getUserId();
|
||||
socialBindStore.saveBind(userId, client, authUser);
|
||||
return Res.ok(new SocialExchangeResult().setResult("bind_success"));
|
||||
}
|
||||
// 登录场景: 查绑定关系
|
||||
Long userId = socialBindStore.findUserIdBySourceAndOpenId(SOURCE, alipayUserId).orElse(null);
|
||||
if (userId == null) {
|
||||
// 未绑定
|
||||
return Res.ok(new SocialExchangeResult().setError("unbind"));
|
||||
}
|
||||
String token = socialLoginHandler.login(userId, client, SOURCE, request, response);
|
||||
return Res.ok(new SocialExchangeResult().setToken(token));
|
||||
} catch (Exception e) {
|
||||
log.error("支付宝授权登录兑换失败: authCode={}, msg={}", authCode, e.getMessage(), e);
|
||||
return Res.ok(new SocialExchangeResult().setError("oauth_failed"));
|
||||
}
|
||||
}
|
||||
|
||||
/// 解析授权场景(未传 mode 时按登录态判断)
|
||||
private SocialAuthMode resolveMode(String mode) {
|
||||
if (StrUtil.isNotBlank(mode)) {
|
||||
try {
|
||||
return SocialAuthMode.valueOf(mode.toUpperCase());
|
||||
} catch (IllegalArgumentException ignored) {
|
||||
}
|
||||
}
|
||||
// 默认: 已登录走绑定, 未登录走登录
|
||||
boolean login = SecurityUtil.isLogin();
|
||||
return login ? SocialAuthMode.BIND : SocialAuthMode.LOGIN;
|
||||
}
|
||||
|
||||
/// 校验支付宝登录已在「三方平台登录配置」中启用
|
||||
private void requireLoginEnabled() {
|
||||
SocialLoginConfig config = socialLoginConfigService.findEnabledBySource(SOURCE);
|
||||
if (config == null) {
|
||||
// 社交登录: 平台配置不存在或未启用
|
||||
throw new OperationFailException("error.social.configNotExist");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ import cn.daxpay.open.platform.iam.result.social.SocialEnabledPlatformResult;
|
||||
import cn.daxpay.open.platform.capability.social.justauth.SocialAuthConfig;
|
||||
import cn.daxpay.open.platform.capability.social.justauth.SocialSourceEnum;
|
||||
import cn.daxpay.open.platform.core.exception.operation.OperationFailException;
|
||||
import cn.daxpay.open.platform.iam.service.social.other.AlipaySocialAuthRequest;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
@@ -30,7 +31,7 @@ import org.springframework.stereotype.Service;
|
||||
/// 配置表 source 全局唯一, 占位记录仅插入一次.
|
||||
///
|
||||
/// **平台级跳转型**(如支付宝): 凭据在独立平台配置中维护, 本表仅存 enabled 占位;
|
||||
/// 「是否启用」与平台凭据解耦——可先启用登录入口, 凭据是否齐全在发起授权时由专用端点校验。
|
||||
/// 「是否启用」与平台凭据解耦——可先启用登录入口, 凭据是否齐全在发起授权时由 [AlipaySocialAuthRequest] 校验。
|
||||
///
|
||||
@Slf4j
|
||||
@Service
|
||||
@@ -135,8 +136,8 @@ public class SocialLoginConfigService {
|
||||
socialLoginConfigManager.updateById(entity);
|
||||
}
|
||||
|
||||
/// 根据平台来源查询已配置且启用的配置(供 SocialAuthRequestFactory / 支付宝端点使用)
|
||||
/// 仅看本表 enabled+configured; 平台凭据完整性由专用端点在发起授权时校验。
|
||||
/// 根据平台来源查询已配置且启用的配置(供 SocialLoginService 授权编排使用)
|
||||
/// 仅看本表 enabled+configured; 平台凭据完整性由 AlipaySocialAuthRequest 在发起授权时校验。
|
||||
public SocialLoginConfig findEnabledBySource(String source) {
|
||||
return socialLoginConfigManager.findEnabledBySource(source).orElse(null);
|
||||
}
|
||||
|
||||
@@ -16,6 +16,8 @@ import cn.daxpay.open.platform.iam.result.social.SocialBindResult;
|
||||
import cn.daxpay.open.platform.iam.result.social.SocialEnabledPlatformResult;
|
||||
import cn.daxpay.open.platform.iam.result.social.SocialExchangeResult;
|
||||
import cn.daxpay.open.platform.iam.enums.SocialAuthMode;
|
||||
import cn.daxpay.open.platform.iam.service.social.other.AlipaySocialAuthRequest;
|
||||
import cn.daxpay.open.platform.iam.service.social.other.AlipaySocialAuthRequestFactory;
|
||||
import cn.daxpay.open.platform.system.entity.config.platform.PlatformUrlConfig;
|
||||
import cn.daxpay.open.platform.system.service.config.PlatformUrlConfigService;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
@@ -33,6 +35,7 @@ import org.springframework.stereotype.Service;
|
||||
/// 前端拿到 code+state 后调用 exchange 接口完成换 token.
|
||||
/// state 仅用于 OAuth2 合规(CSRF), 不携带业务上下文.
|
||||
/// 登录和绑定的区分由回调页路由决定(两个不同的前端页面), exchange 时显式传 source + client.
|
||||
/// 支付宝非标准 OAuth 经 [AlipaySocialAuthRequest] 收口, 对外与标准平台共用本服务入口.
|
||||
///
|
||||
@Slf4j
|
||||
@Service
|
||||
@@ -47,6 +50,8 @@ public class SocialLoginService {
|
||||
|
||||
private final SocialAuthRequestFactory socialAuthRequestFactory;
|
||||
|
||||
private final AlipaySocialAuthRequestFactory alipaySocialAuthRequestFactory;
|
||||
|
||||
private final IamUserSocialBindStore socialBindStore;
|
||||
|
||||
private final IamSocialLoginHandler socialLoginHandler;
|
||||
@@ -84,7 +89,7 @@ public class SocialLoginService {
|
||||
String redirectUri = this.buildRedirectUri(baseUrl, authMode);
|
||||
// 构建授权请求
|
||||
SocialAuthConfig authConfig = socialLoginConfigService.buildAuthConfig(config, redirectUri);
|
||||
SocialAuthRequest request = socialAuthRequestFactory.create(socialSource, authConfig);
|
||||
SocialAuthRequest request = this.createAuthRequest(socialSource, authConfig);
|
||||
// state 仅用于 OAuth2 合规, 不缓存业务上下文
|
||||
String state = IdUtil.fastSimpleUUID();
|
||||
return request.authorize(state);
|
||||
@@ -157,10 +162,18 @@ public class SocialLoginService {
|
||||
if (socialSource == null) {
|
||||
throw new OperationFailException("error.social.unsupportedSource");
|
||||
}
|
||||
SocialAuthRequest authRequest = socialAuthRequestFactory.create(socialSource, authConfig);
|
||||
SocialAuthRequest authRequest = this.createAuthRequest(socialSource, authConfig);
|
||||
return authRequest.login(AuthCallback.of(code, state));
|
||||
}
|
||||
|
||||
/// 按平台创建授权请求: 支付宝走 iam 侧 [AlipaySocialAuthRequest], 其余走 JustAuth 工厂
|
||||
private SocialAuthRequest createAuthRequest(SocialSourceEnum socialSource, SocialAuthConfig authConfig) {
|
||||
if (socialSource == SocialSourceEnum.ALIPAY) {
|
||||
return alipaySocialAuthRequestFactory.create(authConfig);
|
||||
}
|
||||
return socialAuthRequestFactory.create(socialSource, authConfig);
|
||||
}
|
||||
|
||||
/// 解析授权场景(未传 mode 时按登录态判断)
|
||||
private SocialAuthMode resolveMode(String mode) {
|
||||
if (StrUtil.isNotBlank(mode)) {
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
package cn.daxpay.open.platform.iam.service.social.other;
|
||||
|
||||
import cn.daxpay.open.platform.capability.alipay.auth.config.AlipayAuthConfig;
|
||||
import cn.daxpay.open.platform.capability.alipay.auth.result.AlipayAuthResult;
|
||||
import cn.daxpay.open.platform.capability.alipay.auth.service.AlipayAuthCapability;
|
||||
import cn.daxpay.open.platform.capability.social.justauth.SocialAuthConfig;
|
||||
import cn.daxpay.open.platform.capability.social.justauth.SocialSourceEnum;
|
||||
import cn.daxpay.open.platform.capability.social.justauth.exception.SocialException;
|
||||
import cn.daxpay.open.platform.capability.social.justauth.model.AuthCallback;
|
||||
import cn.daxpay.open.platform.capability.social.justauth.model.AuthToken;
|
||||
import cn.daxpay.open.platform.capability.social.justauth.model.AuthUser;
|
||||
import cn.daxpay.open.platform.capability.social.justauth.request.SocialAuthRequest;
|
||||
import cn.daxpay.open.platform.core.exception.operation.OperationFailException;
|
||||
import cn.daxpay.open.platform.iam.service.social.SocialLoginService;
|
||||
import cn.daxpay.open.platform.system.service.config.PlatformAlipayAuthConfigService;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/// # 支付宝社交授权请求
|
||||
///
|
||||
/// 实现 [SocialAuthRequest], 将支付宝非标准 OAuth(`alipay.system.oauth.token`)
|
||||
/// 收口进统一的 Social 编排([SocialLoginService]), 对外与 JustAuth 平台同入口。
|
||||
/// 凭据来自平台级 [PlatformAlipayAuthConfigService], 不使用 [SocialAuthConfig] 的 clientId/secret;
|
||||
/// 公钥/证书模式差异封装在 [AlipayAuthCapability] 内, 本类不分支 authType。
|
||||
///
|
||||
@RequiredArgsConstructor
|
||||
public class AlipaySocialAuthRequest implements SocialAuthRequest {
|
||||
|
||||
/// 授权范围: auth_user(需用户确认, 可获取用户信息)
|
||||
private static final String SCOPE = "auth_user";
|
||||
|
||||
private final SocialAuthConfig config;
|
||||
|
||||
private final AlipayAuthCapability alipayAuthCapability;
|
||||
|
||||
private final PlatformAlipayAuthConfigService platformAlipayAuthConfigService;
|
||||
|
||||
/// 生成支付宝授权地址(仅用平台配置 appId + redirectUri + state)
|
||||
@Override
|
||||
public String authorize(String state) {
|
||||
AlipayAuthConfig capabilityConfig = this.requireCapabilityConfig();
|
||||
// redirectUri 与标准平台一致: 基础 path + /{source}
|
||||
String redirectUri = this.buildRedirectUri();
|
||||
// 平台级配置固定生产环境
|
||||
return alipayAuthCapability.generateAuthUrl(capabilityConfig, redirectUri, SCOPE, state, false);
|
||||
}
|
||||
|
||||
/// 用授权码换 AuthUser(前端已将 auth_code 归一为 code)
|
||||
@Override
|
||||
public AuthUser login(AuthCallback callback) {
|
||||
if (StrUtil.isBlank(callback.getCode())) {
|
||||
// 授权码不能为空
|
||||
throw new SocialException("error.social.authCodeBlank");
|
||||
}
|
||||
AlipayAuthConfig capabilityConfig = this.requireCapabilityConfig();
|
||||
AlipayAuthResult authResult = alipayAuthCapability.getUserId(capabilityConfig, callback.getCode());
|
||||
String alipayUserId = authResult.getUserId();
|
||||
if (StrUtil.isBlank(alipayUserId)) {
|
||||
throw new SocialException("error.social.oauthFailed");
|
||||
}
|
||||
AuthToken token = new AuthToken()
|
||||
.setAccessToken(authResult.getAccessToken())
|
||||
.setOpenId(authResult.getOpenId())
|
||||
.setUnionId(alipayUserId);
|
||||
return new AuthUser()
|
||||
.setSource(SocialSourceEnum.ALIPAY.getCode())
|
||||
.setUuid(alipayUserId)
|
||||
.setNickname("支付宝用户")
|
||||
.setToken(token);
|
||||
}
|
||||
|
||||
/// 支付宝换用户在 [login] 内一次完成, 不单独暴露 accessToken 步骤
|
||||
@Override
|
||||
public AuthToken getAccessToken(AuthCallback callback) {
|
||||
throw new SocialException("error.social.unsupportedSource");
|
||||
}
|
||||
|
||||
/// 支付宝换用户在 [login] 内一次完成, 不单独暴露 userInfo 步骤
|
||||
@Override
|
||||
public AuthUser getUserInfo(AuthToken token) {
|
||||
throw new SocialException("error.social.unsupportedSource");
|
||||
}
|
||||
|
||||
/// 加载并校验平台级支付宝配置完整可用
|
||||
private AlipayAuthConfig requireCapabilityConfig() {
|
||||
AlipayAuthConfig capabilityConfig = platformAlipayAuthConfigService.toCapabilityConfig();
|
||||
if (!alipayAuthCapability.isConfigured(capabilityConfig)) {
|
||||
// 支付宝: 平台级支付宝配置不完整, 请先在「三方平台管理」中配置
|
||||
throw new OperationFailException("error.social.alipayNotConfigured");
|
||||
}
|
||||
return capabilityConfig;
|
||||
}
|
||||
|
||||
/// 构建回调地址(配置基础路径 + 平台编码), 与 [AbstractSocialAuthRequest#buildRedirectUri] 对齐
|
||||
private String buildRedirectUri() {
|
||||
String base = config.getRedirectUri();
|
||||
if (base == null) {
|
||||
base = "";
|
||||
}
|
||||
if (base.endsWith("/")) {
|
||||
base = base.substring(0, base.length() - 1);
|
||||
}
|
||||
return base + "/" + SocialSourceEnum.ALIPAY.getCode();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package cn.daxpay.open.platform.iam.service.social.other;
|
||||
|
||||
import cn.daxpay.open.platform.capability.alipay.auth.service.AlipayAuthCapability;
|
||||
import cn.daxpay.open.platform.capability.social.justauth.SocialAuthConfig;
|
||||
import cn.daxpay.open.platform.capability.social.justauth.request.SocialAuthRequest;
|
||||
import cn.daxpay.open.platform.iam.service.social.SocialLoginService;
|
||||
import cn.daxpay.open.platform.system.service.config.PlatformAlipayAuthConfigService;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/// # 支付宝社交授权请求工厂
|
||||
///
|
||||
/// 在 iam 模块创建 [AlipaySocialAuthRequest], 避免 capability-social 反向依赖 capability-alipay。
|
||||
/// 由 [SocialLoginService] 在 source=alipay 时委托本工厂, 其余平台仍走 [SocialAuthRequestFactory]。
|
||||
///
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class AlipaySocialAuthRequestFactory {
|
||||
|
||||
private final AlipayAuthCapability alipayAuthCapability;
|
||||
|
||||
private final PlatformAlipayAuthConfigService platformAlipayAuthConfigService;
|
||||
|
||||
/// 创建支付宝授权请求(凭据在请求内部从平台配置读取, config 仅提供 redirectUri)
|
||||
public SocialAuthRequest create(SocialAuthConfig config) {
|
||||
return new AlipaySocialAuthRequest(config, alipayAuthCapability, platformAlipayAuthConfigService);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user