update 优化 使用我们自行fork的justauth版本 彻底去除fastjson

This commit is contained in:
疯狂的狮子Li
2026-08-04 14:30:02 +08:00
parent 6d8c0d6d47
commit fba7b40075
12 changed files with 5 additions and 873 deletions
+2 -2
View File
@@ -36,7 +36,7 @@
<!-- 安全认证与加密相关依赖版本 -->
<satoken.version>1.45.0</satoken.version>
<justauth.version>2.0.0</justauth.version>
<justauth.version>3.0.1</justauth.version>
<bouncycastle.version>1.85</bouncycastle.version>
<!-- 缓存、锁与任务调度相关依赖版本 -->
@@ -396,7 +396,7 @@
<!-- JustAuth 的依赖配置-->
<dependency>
<groupId>cn.herodotus.opensteward</groupId>
<groupId>io.github.windtool</groupId>
<artifactId>JustAuth</artifactId>
<version>${justauth.version}</version>
</dependency>
+1 -14
View File
@@ -18,23 +18,10 @@
<dependencies>
<!-- 授权认证 -->
<dependency>
<groupId>cn.herodotus.opensteward</groupId>
<groupId>io.github.windtool</groupId>
<artifactId>JustAuth</artifactId>
</dependency>
<!-- 仅供 justauth 内部解析参数使用 -->
<dependency>
<groupId>com.alibaba.fastjson2</groupId>
<artifactId>fastjson2</artifactId>
<version>2.0.60</version>
</dependency>
<!-- 序列化模块 -->
<dependency>
<groupId>org.dromara</groupId>
<artifactId>ruoyi-common-json</artifactId>
</dependency>
<!-- 缓存服务 -->
<dependency>
<groupId>org.dromara</groupId>
@@ -1,185 +0,0 @@
package me.zhyd.oauth.request;
import com.alibaba.fastjson2.JSONObject;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.config.AuthSource;
import me.zhyd.oauth.constant.Keys;
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.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.utils.HttpUtils;
import me.zhyd.oauth.utils.StringUtils;
import me.zhyd.oauth.utils.UrlBuilder;
/**
* <p>
* 企业微信登录父类
* </p>
*
* @author liguanhua (347826496(a)qq.com)
* @since 1.15.9
*/
public abstract class AbstractAuthWeChatEnterpriseRequest extends AuthDefaultRequest {
/**
* 创建企业微信认证请求。
*
* @param config 授权配置
* @param source 授权来源
*/
public AbstractAuthWeChatEnterpriseRequest(AuthConfig config, AuthSource source) {
super(config, source);
}
/**
* 创建企业微信认证请求。
*
* @param config 授权配置
* @param source 授权来源
* @param authStateCache 授权状态缓存
*/
public AbstractAuthWeChatEnterpriseRequest(AuthConfig config, AuthSource source, AuthStateCache authStateCache) {
super(config, source, authStateCache);
}
/**
* 获取企业微信访问令牌。
*
* @param authCallback 授权回调参数
* @return 访问令牌
*/
@Override
public AuthToken getAccessToken(AuthCallback authCallback) {
String response = doGetAuthorizationCode(accessTokenUrl(null));
JSONObject object = this.checkResponse(response);
return AuthToken.builder()
.accessToken(object.getString(Keys.OAUTH2_ACCESS_TOKEN))
.expireIn(object.getIntValue(Keys.OAUTH2_EXPIRES_IN))
.code(authCallback.getCode())
.build();
}
/**
* 获取企业微信用户信息。
*
* @param authToken 访问令牌
* @return 授权用户信息
*/
@Override
public AuthUser getUserInfo(AuthToken authToken) {
String response = doGetUserInfo(authToken);
JSONObject object = this.checkResponse(response);
// 返回 OpenId 或其他,均代表非当前企业用户,不支持
// https://github.com/justauth/JustAuth/issues/227 修复bug
String userId = null;
if (object.containsKey("userid")) {
userId = object.getString("userid");
} else if (object.containsKey("UserId")) {
userId = object.getString("UserId");
}
if (userId == null) {
throw new AuthException(AuthResponseStatus.UNIDENTIFIED_PLATFORM, source);
}
String userTicket = object.getString("user_ticket");
JSONObject userDetail = getUserDetail(authToken.getAccessToken(), userId, userTicket);
return AuthUser.builder()
.rawUserInfo(userDetail)
.username(userDetail.getString(Keys.NAME))
.nickname(userDetail.getString("alias"))
.avatar(userDetail.getString(Keys.AVATAR))
.location(userDetail.getString(Keys.OAUTH2_SCOPE__ADDRESS))
.email(userDetail.getString(Keys.OAUTH2_SCOPE__EMAIL))
.uuid(userId)
.gender(AuthUserGender.getWechatRealGender(userDetail.getString(Keys.GENDER)))
.token(authToken)
.source(source.toString())
.build();
}
/**
* 校验请求结果
*
* @param response 请求结果
* @return 如果请求结果正常,则返回JSONObject
*/
private JSONObject checkResponse(String response) {
JSONObject object = JSONObject.parseObject(response);
if (object.containsKey(Keys.VARIANT__ERRCODE) && object.getIntValue(Keys.VARIANT__ERRCODE) != 0) {
throw new AuthException(object.getString(Keys.VARIANT__ERRMSG), source);
}
return object;
}
/**
* 返回获取accessToken的url
*
* @param code 授权码
* @return 返回获取accessToken的url
*/
@Override
protected String accessTokenUrl(String code) {
return UrlBuilder.fromBaseUrl(source.accessToken())
.queryParam("corpid", config.getClientId())
.queryParam("corpsecret", config.getClientSecret())
.build();
}
/**
* 返回获取userInfo的url
*
* @param authToken 用户授权后的token
* @return 返回获取userInfo的url
*/
@Override
protected String userInfoUrl(AuthToken authToken) {
return UrlBuilder.fromBaseUrl(source.userInfo())
.queryParam(Keys.OAUTH2_ACCESS_TOKEN, authToken.getAccessToken())
.queryParam(Keys.OAUTH2_CODE, authToken.getCode())
.build();
}
/**
* 用户详情
*
* @param accessToken accessToken
* @param userId 企业内用户id
* @param userTicket 成员票据,用于获取用户信息或敏感信息
* @return 用户详情
*/
private JSONObject getUserDetail(String accessToken, String userId, String userTicket) {
// 用户基础信息
String userInfoUrl = UrlBuilder.fromBaseUrl("https://qyapi.weixin.qq.com/cgi-bin/user/get")
.queryParam(Keys.OAUTH2_ACCESS_TOKEN, accessToken)
.queryParam(Keys.USERID, userId)
.build();
String userInfoResponse = new HttpUtils(config.getHttpConfig()).get(userInfoUrl).getBody();
JSONObject userInfo = checkResponse(userInfoResponse);
// 用户敏感信息
if (StringUtils.isNotEmpty(userTicket)) {
String userDetailUrl = UrlBuilder.fromBaseUrl("https://qyapi.weixin.qq.com/cgi-bin/auth/getuserdetail")
.queryParam(Keys.OAUTH2_ACCESS_TOKEN, accessToken)
.build();
JSONObject param = new JSONObject();
param.put("user_ticket", userTicket);
String userDetailResponse = new HttpUtils(config.getHttpConfig()).post(userDetailUrl, param.toJSONString()).getBody();
JSONObject userDetail = checkResponse(userDetailResponse);
userInfo.putAll(userDetail);
}
return userInfo;
}
}
@@ -1,139 +0,0 @@
package me.zhyd.oauth.request;
import com.alibaba.fastjson2.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.constant.Keys;
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 {
/**
* 创建钉钉 V2 认证请求。
*
* @param config 授权配置
*/
public AuthDingTalkV2Request(AuthConfig config) {
super(config, AuthDefaultSource.DINGTALK_V2);
}
/**
* 创建钉钉 V2 认证请求。
*
* @param config 授权配置
* @param authStateCache 授权状态缓存
*/
public AuthDingTalkV2Request(AuthConfig config, AuthStateCache authStateCache) {
super(config, AuthDefaultSource.DINGTALK_V2, authStateCache);
}
/**
* 生成钉钉 V2 授权地址。
*
* @param state 授权状态
* @return 授权地址
*/
@Override
public String authorize(String state) {
return UrlBuilder.fromBaseUrl(source.authorize())
.queryParam(Keys.OAUTH2_RESPONSE_TYPE, Keys.OAUTH2_CODE)
.queryParam(Keys.OAUTH2_CLIENT_ID, config.getClientId())
.queryParam(Keys.OAUTH2_SCOPE, this.getScopes(",", true, AuthScopeUtils.getDefaultScopes(AuthDingTalkScope.values())))
.queryParam(Keys.OAUTH2_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(Keys.OAUTH2_STATE, getRealState(state))
.build();
}
/**
* 获取钉钉 V2 访问令牌。
*
* @param authCallback 授权回调参数
* @return 访问令牌
*/
@Override
public AuthToken getAccessToken(AuthCallback authCallback) {
Map<String, String> params = new HashMap<>();
params.put("grantType", Keys.OAUTH2_GRANT_TYPE__AUTHORIZATION_CODE);
params.put("clientId", config.getClientId());
params.put("clientSecret", config.getClientSecret());
params.put(Keys.OAUTH2_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();
}
/**
* 获取钉钉 V2 用户信息。
*
* @param authToken 访问令牌
* @return 授权用户信息
*/
@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(Keys.OAUTH2_CODE, code)
.queryParam("clientId", config.getClientId())
.queryParam("clientSecret", config.getClientSecret())
.queryParam("grantType", Keys.OAUTH2_GRANT_TYPE__AUTHORIZATION_CODE)
.build();
}
}
@@ -68,7 +68,7 @@ public class SocialLoginConfigProperties {
private String clientOsType;
/**
* maxkey 服务器地址
* 自托管授权服务器地址
*/
private String serverUrl;
@@ -1,119 +0,0 @@
package org.dromara.common.social.gitea;
import cn.hutool.core.lang.Dict;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
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.request.AuthDefaultRequest;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.json.utils.JsonUtils;
/**
* @author lcry
*/
@Slf4j
public class AuthGiteaRequest extends AuthDefaultRequest {
/**
* 服务器地址。
*/
public static final String SERVER_URL = SpringUtils.getProperty("justauth.type.gitea.server-url");
/**
* 设定归属域
*/
public AuthGiteaRequest(AuthConfig config) {
super(config, AuthGiteaSource.GITEA);
}
/**
* 创建 Gitea 认证请求。
*
* @param config 授权配置
* @param authStateCache 授权状态缓存
*/
public AuthGiteaRequest(AuthConfig config, AuthStateCache authStateCache) {
super(config, AuthGiteaSource.GITEA, authStateCache);
}
/**
* 获取 Gitea 访问令牌。
*
* @param authCallback 授权回调参数
* @return 访问令牌
*/
@Override
public AuthToken getAccessToken(AuthCallback authCallback) {
String body = doPostAuthorizationCode(authCallback.getCode());
Dict object = JsonUtils.parseMap(body);
// oauth/token 验证异常
if (object.containsKey("error")) {
throw new AuthException(object.getStr("error_description"));
}
// user 验证异常
if (object.containsKey("message")) {
throw new AuthException(object.getStr("message"));
}
return AuthToken.builder()
.accessToken(object.getStr("access_token"))
.refreshToken(object.getStr("refresh_token"))
.idToken(object.getStr("id_token"))
.tokenType(object.getStr("token_type"))
.scope(object.getStr("scope"))
.build();
}
/**
* 使用授权码换取 Gitea 访问令牌响应。
*
* @param code 授权码
* @return 令牌接口响应体
*/
@Override
protected String doPostAuthorizationCode(String code) {
HttpRequest request = HttpRequest.post(source.accessToken())
.form("client_id", config.getClientId())
.form("client_secret", config.getClientSecret())
.form("grant_type", "authorization_code")
.form("code", code)
.form("redirect_uri", config.getRedirectUri());
HttpResponse response = request.execute();
return response.body();
}
/**
* 获取 Gitea 用户信息。
*
* @param authToken 访问令牌
* @return 授权用户信息
*/
@Override
public AuthUser getUserInfo(AuthToken authToken) {
String body = doGetUserInfo(authToken);
Dict object = JsonUtils.parseMap(body);
// oauth/token 验证异常
if (object.containsKey("error")) {
throw new AuthException(object.getStr("error_description"));
}
// user 验证异常
if (object.containsKey("message")) {
throw new AuthException(object.getStr("message"));
}
return AuthUser.builder()
.uuid(object.getStr("sub"))
.username(object.getStr("name"))
.nickname(object.getStr("preferred_username"))
.avatar(object.getStr("picture"))
.email(object.getStr("email"))
.token(authToken)
.source(source.toString())
.build();
}
}
@@ -1,50 +0,0 @@
package org.dromara.common.social.gitea;
import me.zhyd.oauth.config.AuthSource;
import me.zhyd.oauth.request.AuthDefaultRequest;
/**
* gitea Oauth2 默认接口说明
*
* @author lcry
*/
public enum AuthGiteaSource implements AuthSource {
/**
* 自己搭建的 gitea 私服
*/
GITEA {
/**
* 授权的api
*/
@Override
public String authorize() {
return AuthGiteaRequest.SERVER_URL + "/login/oauth/authorize";
}
/**
* 获取accessToken的api
*/
@Override
public String accessToken() {
return AuthGiteaRequest.SERVER_URL + "/login/oauth/access_token";
}
/**
* 获取用户信息的api
*/
@Override
public String userInfo() {
return AuthGiteaRequest.SERVER_URL + "/login/oauth/userinfo";
}
/**
* 平台对应的 AuthRequest 实现类,必须继承自 {@link AuthDefaultRequest}
*/
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthGiteaRequest.class;
}
}
}
@@ -1,101 +0,0 @@
package org.dromara.common.social.maxkey;
import cn.hutool.core.lang.Dict;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
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.request.AuthDefaultRequest;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.json.utils.JsonUtils;
/**
* @author 长春叭哥 2023年03月26日
*/
public class AuthMaxKeyRequest extends AuthDefaultRequest {
/**
* 服务器地址。
*/
public static final String SERVER_URL = SpringUtils.getProperty("justauth.type.maxkey.server-url");
/**
* 设定归属域
*/
public AuthMaxKeyRequest(AuthConfig config) {
super(config, AuthMaxKeySource.MAXKEY);
}
/**
* 创建 MaxKey 认证请求。
*
* @param config 授权配置
* @param authStateCache 授权状态缓存
*/
public AuthMaxKeyRequest(AuthConfig config, AuthStateCache authStateCache) {
super(config, AuthMaxKeySource.MAXKEY, authStateCache);
}
/**
* 获取 MaxKey 访问令牌。
*
* @param authCallback 授权回调参数
* @return 访问令牌
*/
@Override
public AuthToken getAccessToken(AuthCallback authCallback) {
String body = doPostAuthorizationCode(authCallback.getCode());
Dict object = JsonUtils.parseMap(body);
// oauth/token 验证异常
if (object.containsKey("error")) {
throw new AuthException(object.getStr("error_description"));
}
// user 验证异常
if (object.containsKey("message")) {
throw new AuthException(object.getStr("message"));
}
return AuthToken.builder()
.accessToken(object.getStr("access_token"))
.refreshToken(object.getStr("refresh_token"))
.idToken(object.getStr("id_token"))
.tokenType(object.getStr("token_type"))
.scope(object.getStr("scope"))
.build();
}
/**
* 获取 MaxKey 用户信息。
*
* @param authToken 访问令牌
* @return 授权用户信息
*/
@Override
public AuthUser getUserInfo(AuthToken authToken) {
String body = doGetUserInfo(authToken);
Dict object = JsonUtils.parseMap(body);
// oauth/token 验证异常
if (object.containsKey("error")) {
throw new AuthException(object.getStr("error_description"));
}
// user 验证异常
if (object.containsKey("message")) {
throw new AuthException(object.getStr("message"));
}
return AuthUser.builder()
.uuid(object.getStr("userId"))
.username(object.getStr("username"))
.nickname(object.getStr("displayName"))
.avatar(object.getStr("avatar_url"))
.blog(object.getStr("web_url"))
.company(object.getStr("organization"))
.location(object.getStr("location"))
.email(object.getStr("email"))
.remark(object.getStr("bio"))
.token(authToken)
.source(source.toString())
.build();
}
}
@@ -1,52 +0,0 @@
package org.dromara.common.social.maxkey;
import me.zhyd.oauth.config.AuthSource;
import me.zhyd.oauth.request.AuthDefaultRequest;
/**
* Oauth2 默认接口说明
*
* @author 长春叭哥 2023年03月26日
*
*/
public enum AuthMaxKeySource implements AuthSource {
/**
* 自己搭建的 maxkey 私服
*/
MAXKEY {
/**
* 授权的api
*/
@Override
public String authorize() {
return AuthMaxKeyRequest.SERVER_URL + "/sign/authz/oauth/v20/authorize";
}
/**
* 获取accessToken的api
*/
@Override
public String accessToken() {
return AuthMaxKeyRequest.SERVER_URL + "/sign/authz/oauth/v20/token";
}
/**
* 获取用户信息的api
*/
@Override
public String userInfo() {
return AuthMaxKeyRequest.SERVER_URL + "/sign/api/oauth/v20/me";
}
/**
* 平台对应的 AuthRequest 实现类,必须继承自 {@link AuthDefaultRequest}
*/
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthMaxKeyRequest.class;
}
}
}
@@ -1,156 +0,0 @@
package org.dromara.common.social.topiam;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.xkcoding.http.support.HttpHeader;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.cache.AuthStateCache;
import me.zhyd.oauth.config.AuthConfig;
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.request.AuthDefaultRequest;
import me.zhyd.oauth.utils.HttpUtils;
import me.zhyd.oauth.utils.UrlBuilder;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.json.utils.JsonUtils;
import static org.dromara.common.social.topiam.AuthTopIamSource.TOPIAM;
/**
* TopIAM 认证请求
*
* @author xlsea
* @since 2024-01-06
*/
@Slf4j
public class AuthTopIamRequest extends AuthDefaultRequest {
/**
* 服务器地址。
*/
public static final String SERVER_URL = SpringUtils.getProperty("justauth.type.topiam.server-url");
/**
* 设定归属域
*/
public AuthTopIamRequest(AuthConfig config) {
super(config, TOPIAM);
}
/**
* 创建 TopIAM 认证请求。
*
* @param config 授权配置
* @param authStateCache 授权状态缓存
*/
public AuthTopIamRequest(AuthConfig config, AuthStateCache authStateCache) {
super(config, TOPIAM, authStateCache);
}
/**
* 获取 TopIAM 访问令牌。
*
* @param authCallback 授权回调参数
* @return 访问令牌
*/
@Override
public AuthToken getAccessToken(AuthCallback authCallback) {
String body = doPostAuthorizationCode(authCallback.getCode());
Dict object = JsonUtils.parseMap(body);
checkResponse(object);
return AuthToken.builder()
.accessToken(object.getStr("access_token"))
.refreshToken(object.getStr("refresh_token"))
.idToken(object.getStr("id_token"))
.tokenType(object.getStr("token_type"))
.scope(object.getStr("scope"))
.build();
}
/**
* 获取 TopIAM 用户信息。
*
* @param authToken 访问令牌
* @return 授权用户信息
*/
@Override
public AuthUser getUserInfo(AuthToken authToken) {
String body = doGetUserInfo(authToken);
Dict object = JsonUtils.parseMap(body);
checkResponse(object);
return AuthUser.builder()
.uuid(object.getStr("sub"))
.username(object.getStr("preferred_username"))
.nickname(object.getStr("nickname"))
.avatar(object.getStr("picture"))
.email(object.getStr("email"))
.token(authToken)
.source(source.toString())
.build();
}
/**
* 使用授权码换取 TopIAM 访问令牌响应。
*
* @param code 授权码
* @return 令牌接口响应体
*/
@Override
protected String doPostAuthorizationCode(String code) {
HttpRequest request = HttpRequest.post(source.accessToken())
.header("Authorization", "Basic " + Base64.encode("%s:%s".formatted(config.getClientId(), config.getClientSecret())))
.form("grant_type", "authorization_code")
.form("code", code)
.form("redirect_uri", config.getRedirectUri());
HttpResponse response = request.execute();
return response.body();
}
/**
* 获取 TopIAM 用户信息接口响应。
*
* @param authToken 访问令牌
* @return 用户信息响应体
*/
@Override
protected String doGetUserInfo(AuthToken authToken) {
return new HttpUtils(config.getHttpConfig()).get(source.userInfo(), null, new HttpHeader()
.add("Content-Type", "application/json")
.add("Authorization", "Bearer " + authToken.getAccessToken()), false).getBody();
}
/**
* 生成 TopIAM 授权地址。
*
* @param state 授权状态
* @return 授权地址
*/
@Override
public String authorize(String state) {
return UrlBuilder.fromBaseUrl(super.authorize(state))
.queryParam("scope", StrUtil.join("%20", config.getScopes()))
.build();
}
/**
* 校验 TopIAM 接口响应。
*
* @param object 响应内容
*/
private static void checkResponse(Dict object) {
// oauth/token 验证异常
if (object.containsKey("error")) {
throw new AuthException(object.getStr("error_description"));
}
// user 验证异常
if (object.containsKey("message")) {
throw new AuthException(object.getStr("message"));
}
}
}
@@ -1,51 +0,0 @@
package org.dromara.common.social.topiam;
import me.zhyd.oauth.config.AuthSource;
import me.zhyd.oauth.request.AuthDefaultRequest;
/**
* Oauth2 默认接口说明
*
* @author xlsea
* @since 2024-01-06
*/
public enum AuthTopIamSource implements AuthSource {
/**
* 测试
*/
TOPIAM {
/**
* 授权的api
*/
@Override
public String authorize() {
return AuthTopIamRequest.SERVER_URL + "/oauth2/auth";
}
/**
* 获取accessToken的api
*/
@Override
public String accessToken() {
return AuthTopIamRequest.SERVER_URL + "/oauth2/token";
}
/**
* 获取用户信息的api
*/
@Override
public String userInfo() {
return AuthTopIamRequest.SERVER_URL + "/oauth2/userinfo";
}
/**
* 平台对应的 AuthRequest 实现类,必须继承自 {@link AuthDefaultRequest}
*/
@Override
public Class<? extends AuthDefaultRequest> getTargetClass() {
return AuthTopIamRequest.class;
}
}
}
@@ -10,9 +10,6 @@ import me.zhyd.oauth.request.*;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.social.config.properties.SocialLoginConfigProperties;
import org.dromara.common.social.config.properties.SocialProperties;
import org.dromara.common.social.gitea.AuthGiteaRequest;
import org.dromara.common.social.maxkey.AuthMaxKeyRequest;
import org.dromara.common.social.topiam.AuthTopIamRequest;
/**
* 认证授权工具类
@@ -58,6 +55,7 @@ public class SocialUtils {
.clientId(obj.getClientId())
.clientSecret(obj.getClientSecret())
.redirectUri(obj.getRedirectUri())
.serverUrl(obj.getServerUrl())
.scopes(obj.getScopes());
return switch (source.toLowerCase()) {
case "dingtalk" -> new AuthDingTalkV2Request(builder.build(), STATE_CACHE);