diff --git a/CHANGELOGS.md b/CHANGELOGS.md
index aa90ed5..695f032 100644
--- a/CHANGELOGS.md
+++ b/CHANGELOGS.md
@@ -1,14 +1,15 @@
## 1.16.7
-### 2024/08/03
+### 2024/12/14
- 新增
- 添加`appleid`社交登录能力。 [Github#192](https://github.com/justauth/JustAuth/pull/192)
+ - 添加`支付宝证书模式`登录能力(原支持的公钥登录模式依然可用)。
- 添加`figma`社交登录能力。 [Gitee#41](https://gitee.com/yadong.zhang/JustAuth/pulls/41)
- 添加新版`企业微信扫码`登录能力。 [Github Issue#165](https://github.com/justauth/JustAuth/issues/165)
- 添加新版`钉钉扫码`登录能力。 [Gitee Issue#I73FZL](https://gitee.com/yadong.zhang/JustAuth/issues/I73FZL)
- 添加新版`华为`登录能力,原`AuthHuaweiRequest`会在后面版本被弃用,如有使用,请切换到`AuthHuaweiV3Request`
- - 新增微信小程序授权登录
+ - 添加`微信小程序`登录能力。
- 优化
- 更新 Google 端点地址。[Github #198](https://github.com/justauth/JustAuth/pull/198)
- Amazon PKCE 中的 `code_verifier` 基于 `state` 缓存
diff --git a/pom.xml b/pom.xml
index 020ea2d..a60abfc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -61,7 +61,7 @@
1.18.30
4.13.2
1.2.83
- 4.17.5.ALL
+ 4.39.165.ALL
0.8.2
0.12.3
1.78
diff --git a/src/main/java/me/zhyd/oauth/request/AuthAlipayCertRequest.java b/src/main/java/me/zhyd/oauth/request/AuthAlipayCertRequest.java
new file mode 100644
index 0000000..6277ec9
--- /dev/null
+++ b/src/main/java/me/zhyd/oauth/request/AuthAlipayCertRequest.java
@@ -0,0 +1,152 @@
+package me.zhyd.oauth.request;
+
+
+import com.alibaba.fastjson.JSONObject;
+import com.alipay.api.AlipayApiException;
+import com.alipay.api.AlipayClient;
+import com.alipay.api.AlipayConfig;
+import com.alipay.api.DefaultAlipayClient;
+import com.alipay.api.request.AlipaySystemOauthTokenRequest;
+import com.alipay.api.request.AlipayUserInfoShareRequest;
+import com.alipay.api.response.AlipaySystemOauthTokenResponse;
+import com.alipay.api.response.AlipayUserInfoShareResponse;
+import me.zhyd.oauth.config.AuthConfig;
+import me.zhyd.oauth.enums.AuthResponseStatus;
+import me.zhyd.oauth.enums.AuthUserGender;
+import me.zhyd.oauth.exception.AuthException;
+import me.zhyd.oauth.model.AuthCallback;
+import me.zhyd.oauth.model.AuthResponse;
+import me.zhyd.oauth.model.AuthToken;
+import me.zhyd.oauth.model.AuthUser;
+import me.zhyd.oauth.utils.StringUtils;
+import me.zhyd.oauth.utils.UrlBuilder;
+
+import static me.zhyd.oauth.config.AuthDefaultSource.ALIPAY;
+
+/**
+ * 支付宝证书模式登录
+ *
+ * @since 1.16.7
+ */
+public class AuthAlipayCertRequest extends AuthDefaultRequest {
+
+ private final AlipayClient alipayClient;
+
+ public AuthAlipayCertRequest(AuthConfig config, AlipayConfig alipayConfig) {
+ super(config, ALIPAY);
+ try {
+ this.alipayClient = new DefaultAlipayClient(alipayConfig);
+ } catch (AlipayApiException e) {
+ throw new AuthException(e);
+ }
+ }
+
+ @Override
+ protected void checkCode(AuthCallback authCallback) {
+ if (StringUtils.isEmpty(authCallback.getAuth_code())) {
+ throw new AuthException(AuthResponseStatus.ILLEGAL_CODE, source);
+ }
+ }
+
+ @Override
+ public AuthToken getAccessToken(AuthCallback authCallback) {
+ AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
+ request.setGrantType("authorization_code");
+ request.setCode(authCallback.getAuth_code());
+ AlipaySystemOauthTokenResponse response;
+ try {
+ response = this.alipayClient.certificateExecute(request);
+ } catch (Exception e) {
+ throw new AuthException(e);
+ }
+ if (!response.isSuccess()) {
+ throw new AuthException(response.getSubMsg());
+ }
+ return AuthToken.builder()
+ .accessToken(response.getAccessToken())
+ .uid(response.getUserId())
+ .expireIn(Integer.parseInt(response.getExpiresIn()))
+ .refreshToken(response.getRefreshToken())
+ .build();
+ }
+
+
+ /**
+ * 刷新access token (续期)
+ *
+ * @param authToken 登录成功后返回的Token信息
+ * @return AuthResponse
+ */
+ @Override
+ public AuthResponse refresh(AuthToken authToken) {
+ AlipaySystemOauthTokenRequest request = new AlipaySystemOauthTokenRequest();
+ request.setGrantType("refresh_token");
+ request.setRefreshToken(authToken.getRefreshToken());
+ AlipaySystemOauthTokenResponse response = null;
+ try {
+ response = this.alipayClient.certificateExecute(request);
+ } catch (Exception e) {
+ throw new AuthException(e);
+ }
+ if (!response.isSuccess()) {
+ throw new AuthException(response.getSubMsg());
+ }
+ return AuthResponse.builder()
+ .code(AuthResponseStatus.SUCCESS.getCode())
+ .data(AuthToken.builder()
+ .accessToken(response.getAccessToken())
+ .uid(response.getUserId())
+ .expireIn(Integer.parseInt(response.getExpiresIn()))
+ .refreshToken(response.getRefreshToken())
+ .build())
+ .build();
+ }
+
+ @Override
+ public AuthUser getUserInfo(AuthToken authToken) {
+ String accessToken = authToken.getAccessToken();
+ AlipayUserInfoShareRequest request = new AlipayUserInfoShareRequest();
+ AlipayUserInfoShareResponse response = null;
+ try {
+ response = this.alipayClient.certificateExecute(request, accessToken);
+ } catch (AlipayApiException e) {
+ throw new AuthException(e.getErrMsg(), e);
+ }
+ if (!response.isSuccess()) {
+ throw new AuthException(response.getSubMsg());
+ }
+
+ String province = response.getProvince(), city = response.getCity();
+ String location = String.format("%s %s", StringUtils.isEmpty(province) ? "" : province, StringUtils.isEmpty(city) ? "" : city);
+
+ return AuthUser.builder()
+ .rawUserInfo(JSONObject.parseObject(JSONObject.toJSONString(response)))
+ .uuid(response.getOpenId())
+ .username(StringUtils.isEmpty(response.getUserName()) ? response.getNickName() : response.getUserName())
+ .nickname(response.getNickName())
+ .avatar(response.getAvatar())
+ .location(location)
+ .gender(AuthUserGender.getRealGender(response.getGender()))
+ .token(authToken)
+ .source(source.toString())
+ .build();
+ }
+
+
+ /**
+ * 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
+ *
+ * @param state state 验证授权流程的参数,可以防止csrf
+ * @return 返回授权地址
+ * @since 1.9.3
+ */
+ @Override
+ public String authorize(String state) {
+ return UrlBuilder.fromBaseUrl(source.authorize())
+ .queryParam("app_id", config.getClientId())
+ .queryParam("scope", "auth_user")
+ .queryParam("redirect_uri", config.getRedirectUri())
+ .queryParam("state", getRealState(state))
+ .build();
+ }
+}
diff --git a/src/main/java/me/zhyd/oauth/request/AuthAlipayRequest.java b/src/main/java/me/zhyd/oauth/request/AuthAlipayRequest.java
index b832346..428ca86 100644
--- a/src/main/java/me/zhyd/oauth/request/AuthAlipayRequest.java
+++ b/src/main/java/me/zhyd/oauth/request/AuthAlipayRequest.java
@@ -26,7 +26,7 @@
import java.net.InetSocketAddress;
/**
- * 支付宝登录
+ * 支付宝公钥模式登录
*
* @author yadong.zhang (yadong.zhang0415(a)gmail.com)
* @since 1.0.1