From 5f2c4205a50559ebd9f0c808bd37ab3ed0fa16fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=96=AF=E7=8B=82=E7=9A=84=E7=8B=AE=E5=AD=90Li?= <15040126243@163.com> Date: Sun, 28 Sep 2025 16:18:02 +0800 Subject: [PATCH] =?UTF-8?q?fix=20=E4=BF=AE=E5=A4=8D=20=E4=B8=89=E6=96=B9?= =?UTF-8?q?=E6=8E=88=E6=9D=83=20=E9=92=89=E9=92=89=E5=9B=9E=E8=B0=83?= =?UTF-8?q?=E5=9C=B0=E5=9D=80=E6=9C=AA=E8=BF=9B=E8=A1=8Curl=E7=BC=96?= =?UTF-8?q?=E7=A0=81=E9=97=AE=E9=A2=98=20=E7=94=B1=E5=85=A8=E5=B1=80?= =?UTF-8?q?=E7=BC=96=E7=A0=81=E6=94=B9=E4=B8=BA=E5=8D=95=E7=8B=AC=E7=BC=96?= =?UTF-8?q?=E7=A0=81=20=E9=81=BF=E5=85=8D=E5=85=B6=E4=BB=96=E4=B8=89?= =?UTF-8?q?=E6=96=B9=E8=B0=83=E7=94=A8=E9=87=8D=E5=A4=8D=E7=BC=96=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../oauth/request/AuthDingTalkV2Request.java | 109 ++++++++++++++++++ .../common/social/utils/SocialUtils.java | 5 +- 2 files changed, 110 insertions(+), 4 deletions(-) create mode 100644 ruoyi-common/ruoyi-common-social/src/main/java/me/zhyd/oauth/request/AuthDingTalkV2Request.java diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/me/zhyd/oauth/request/AuthDingTalkV2Request.java b/ruoyi-common/ruoyi-common-social/src/main/java/me/zhyd/oauth/request/AuthDingTalkV2Request.java new file mode 100644 index 000000000..86532d48a --- /dev/null +++ b/ruoyi-common/ruoyi-common-social/src/main/java/me/zhyd/oauth/request/AuthDingTalkV2Request.java @@ -0,0 +1,109 @@ +package me.zhyd.oauth.request; + +import com.alibaba.fastjson.JSONObject; +import com.xkcoding.http.support.HttpHeader; +import me.zhyd.oauth.cache.AuthStateCache; +import me.zhyd.oauth.config.AuthConfig; +import me.zhyd.oauth.config.AuthDefaultSource; +import me.zhyd.oauth.enums.scope.AuthDingTalkScope; +import me.zhyd.oauth.exception.AuthException; +import me.zhyd.oauth.model.AuthCallback; +import me.zhyd.oauth.model.AuthToken; +import me.zhyd.oauth.model.AuthUser; +import me.zhyd.oauth.utils.AuthScopeUtils; +import me.zhyd.oauth.utils.GlobalAuthUtils; +import me.zhyd.oauth.utils.HttpUtils; +import me.zhyd.oauth.utils.UrlBuilder; + +import java.util.HashMap; +import java.util.Map; + +/** + * 新版钉钉二维码登录 + * + * @author yadong.zhang (yadong.zhang0415(a)gmail.com) + * @since 1.16.7 + */ +public class AuthDingTalkV2Request extends AuthDefaultRequest { + + public AuthDingTalkV2Request(AuthConfig config) { + super(config, AuthDefaultSource.DINGTALK_V2); + } + + public AuthDingTalkV2Request(AuthConfig config, AuthStateCache authStateCache) { + super(config, AuthDefaultSource.DINGTALK_V2, authStateCache); + } + + @Override + public String authorize(String state) { + return UrlBuilder.fromBaseUrl(source.authorize()) + .queryParam("response_type", "code") + .queryParam("client_id", config.getClientId()) + .queryParam("scope", this.getScopes(",", true, AuthScopeUtils.getDefaultScopes(AuthDingTalkScope.values()))) + .queryParam("redirect_uri", GlobalAuthUtils.urlEncode(config.getRedirectUri())) + .queryParam("prompt", "consent") + .queryParam("org_type", config.getDingTalkOrgType()) + .queryParam("corpId", config.getDingTalkCorpId()) + .queryParam("exclusiveLogin", config.isDingTalkExclusiveLogin()) + .queryParam("exclusiveCorpId", config.getDingTalkExclusiveCorpId()) + .queryParam("state", getRealState(state)) + .build(); + } + + @Override + public AuthToken getAccessToken(AuthCallback authCallback) { + Map params = new HashMap<>(); + params.put("grantType", "authorization_code"); + params.put("clientId", config.getClientId()); + params.put("clientSecret", config.getClientSecret()); + params.put("code", authCallback.getCode()); + String response = new HttpUtils(config.getHttpConfig()).post(this.source.accessToken(), JSONObject.toJSONString(params)).getBody(); + JSONObject accessTokenObject = JSONObject.parseObject(response); + if (!accessTokenObject.containsKey("accessToken")) { + throw new AuthException(JSONObject.toJSONString(response), source); + } + return AuthToken.builder() + .accessToken(accessTokenObject.getString("accessToken")) + .refreshToken(accessTokenObject.getString("refreshToken")) + .expireIn(accessTokenObject.getIntValue("expireIn")) + .corpId(accessTokenObject.getString("corpId")) + .build(); + } + + @Override + public AuthUser getUserInfo(AuthToken authToken) { + HttpHeader header = new HttpHeader(); + header.add("x-acs-dingtalk-access-token", authToken.getAccessToken()); + + String response = new HttpUtils(config.getHttpConfig()).get(this.source.userInfo(), null, header, false).getBody(); + JSONObject object = JSONObject.parseObject(response); + + authToken.setOpenId(object.getString("openId")); + authToken.setUnionId(object.getString("unionId")); + return AuthUser.builder() + .rawUserInfo(object) + .uuid(object.getString("unionId")) + .username(object.getString("nick")) + .nickname(object.getString("nick")) + .avatar(object.getString("avatarUrl")) + .snapshotUser(object.getBooleanValue("visitor")) + .token(authToken) + .source(source.toString()) + .build(); + } + + /** + * 返回获取accessToken的url + * + * @param code 授权码 + * @return 返回获取accessToken的url + */ + protected String accessTokenUrl(String code) { + return UrlBuilder.fromBaseUrl(source.accessToken()) + .queryParam("code", code) + .queryParam("clientId", config.getClientId()) + .queryParam("clientSecret", config.getClientSecret()) + .queryParam("grantType", "authorization_code") + .build(); + } +} diff --git a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java index 151d84ce2..3f7924d9b 100644 --- a/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java +++ b/ruoyi-common/ruoyi-common-social/src/main/java/org/dromara/common/social/utils/SocialUtils.java @@ -14,9 +14,6 @@ import org.dromara.common.social.gitea.AuthGiteaRequest; import org.dromara.common.social.maxkey.AuthMaxKeyRequest; import org.dromara.common.social.topiam.AuthTopIamRequest; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; - /** * 认证授权工具类 * @@ -43,7 +40,7 @@ public class SocialUtils { AuthConfig.AuthConfigBuilder builder = AuthConfig.builder() .clientId(obj.getClientId()) .clientSecret(obj.getClientSecret()) - .redirectUri(URLEncoder.encode(obj.getRedirectUri(), StandardCharsets.UTF_8)) + .redirectUri(obj.getRedirectUri()) .scopes(obj.getScopes()); return switch (source.toLowerCase()) { case "dingtalk" -> new AuthDingTalkV2Request(builder.build(), STATE_CACHE);