diff --git a/CHANGELOGS.md b/CHANGELOGS.md index 7747f1095a4147211877c053b165268798c68895..f0d52765122c1dd58909d13356d31fd689c65133 100644 --- a/CHANGELOGS.md +++ b/CHANGELOGS.md @@ -1,3 +1,14 @@ +## 1.16.3 + +### 2021/8/** + +- 发布 v1.16.3 +- PR + - 合并 Gitee PR ([#27](https://gitee.com/yadong.zhang/JustAuth/pulls/27)) +- 修改 + 在 Gitee PR ([#27](https://gitee.com/yadong.zhang/JustAuth/pulls/27)) 的基础上重构代码,增加 Builder 方式创建 AuthRequest + + ## 1.16.2 ### 2021/7/28 diff --git a/README.md b/README.md index 5c86ac4ad6e190a90d799c5acadfad3d9eb116f9..b558ccf41bab9f89293b647cb45ac9c7917362b4 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ JustAuth 集成了诸如:Github、Gitee、支付宝、新浪微博、微信、 ## 快速开始 -- 引入依赖 +### 引入依赖 ```xml me.zhyd.oauth @@ -69,22 +69,8 @@ JustAuth 集成了诸如:Github、Gitee、支付宝、新浪微博、微信、 1.16.2 ``` -- 调用api -```java -// 创建授权request -AuthRequest authRequest = new AuthGiteeRequest(AuthConfig.builder() - .clientId("clientId") - .clientSecret("clientSecret") - .redirectUri("redirectUri") - .build()); -// 生成授权页面 -authRequest.authorize("state"); -// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的参数 -// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state -authRequest.login(callback); -``` -如下**任选一种** HTTP 工具 依赖,_项目内如果已有,请忽略。另外需要特别注意,如果项目中已经引入了低版本的依赖,请先排除低版本以后来,引入高版本或者最新版本的依赖_ +如下**任选一种** HTTP 工具 依赖,_项目内如果已有,请忽略。另外需要特别注意,如果项目中已经引入了低版本的依赖,请先排除低版本依赖后,引入高版本或者最新版本的依赖_ - hutool-http @@ -92,7 +78,7 @@ authRequest.login(callback); cn.hutool hutool-http - 5.2.5 + 5.7.7 ``` @@ -102,7 +88,7 @@ authRequest.login(callback); org.apache.httpcomponents httpclient - 4.5.12 + 4.5.13 ``` @@ -112,9 +98,78 @@ authRequest.login(callback); com.squareup.okhttp3 okhttp - 4.4.1 + 4.9.1 ``` + +### 调用api + +#### 普通方式 + +```java +// 创建授权request +AuthRequest authRequest = new AuthGiteeRequest(AuthConfig.builder() + .clientId("clientId") + .clientSecret("clientSecret") + .redirectUri("redirectUri") + .build()); +// 生成授权页面 +authRequest.authorize("state"); +// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的参数 +// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state +authRequest.login(callback); +``` + +#### Builder 方式一 + +静态配置 `AuthConfig` + +```java +AuthRequest authRequest = AuthRequestBuilder.builder() + .source("github") + .authConfig(AuthConfig.builder() + .clientId("clientId") + .clientSecret("clientSecret") + .redirectUri("redirectUri") + .build()) + .build(); +// 生成授权页面 + authRequest.authorize("state"); +// 授权登录后会返回code(auth_code(仅限支付宝))、state,1.8.0版本后,可以用AuthCallback类作为回调接口的参数 +// 注:JustAuth默认保存state的时效为3分钟,3分钟内未使用则会自动清除过期的state + authRequest.login(callback); +``` + +#### Builder 方式二 + +静态获取并配置 `AuthConfig` + +```java +AuthRequest authRequest = AuthRequestBuilder.builder() + .source("gitee") + .authConfig((source) -> { + // 通过 source 动态获取 AuthConfig + // 此处可以灵活的从 sql 中取配置也可以从配置文件中取配置 + return AuthConfig.builder() + .clientId("clientId") + .clientSecret("clientSecret") + .redirectUri("redirectUri") + .build(); + }) + .build(); +Assert.assertTrue(authRequest instanceof AuthGiteeRequest); +System.out.println(authRequest.authorize(AuthStateUtils.createState())); +``` + +#### Builder 方式支持自定义的平台 + +```java +AuthRequest authRequest = AuthRequestBuilder.builder() + // 关键点:将自定义实现的 AuthSource 配置上 + .extendSource(AuthExtendSource.values()) + // ... 其他内容不变,参考上面的示例 + .build(); +``` ## 赞助和支持 diff --git a/src/main/java/me/zhyd/oauth/AuthRequestBuilder.java b/src/main/java/me/zhyd/oauth/AuthRequestBuilder.java new file mode 100644 index 0000000000000000000000000000000000000000..9bf86fa60152416208aeb9220360c09f413f6786 --- /dev/null +++ b/src/main/java/me/zhyd/oauth/AuthRequestBuilder.java @@ -0,0 +1,98 @@ +package me.zhyd.oauth; + +import me.zhyd.oauth.cache.AuthStateCache; +import me.zhyd.oauth.config.AuthConfig; +import me.zhyd.oauth.config.AuthDefaultSource; +import me.zhyd.oauth.config.AuthSource; +import me.zhyd.oauth.exception.AuthException; +import me.zhyd.oauth.request.AuthDefaultRequest; +import me.zhyd.oauth.request.AuthRequest; +import me.zhyd.oauth.utils.StringUtils; + +import java.util.Arrays; +import java.util.function.Function; + +/** + * 快捷的构建 AuthRequest + * + * @author yadong.zhang (yadong.zhang0415(a)gmail.com) + * @version 1.0.0 + * @since 1.16.3 + */ +public class AuthRequestBuilder { + private String source; + private AuthConfig authConfig; + private AuthStateCache authStateCache; + private AuthSource[] extendSource; + + private AuthRequestBuilder() { + + } + + public static AuthRequestBuilder builder() { + return new AuthRequestBuilder(); + } + + public AuthRequestBuilder source(String source) { + this.source = source; + return this; + } + + public AuthRequestBuilder authConfig(AuthConfig authConfig) { + this.authConfig = authConfig; + return this; + } + + public AuthRequestBuilder authConfig(Function authConfig) { + this.authConfig = authConfig.apply(this.source); + return this; + } + + public AuthRequestBuilder authStateCache(AuthStateCache authStateCache) { + this.authStateCache = authStateCache; + return this; + } + + public AuthRequestBuilder extendSource(AuthSource... extendSource) { + this.extendSource = extendSource; + return this; + } + + public AuthRequest build() { + if (StringUtils.isEmpty(this.source)) { + throw new AuthException("未配置 source"); + } + if (null == this.authConfig) { + throw new AuthException("未配置 AuthConfig"); + } + // 合并 JustAuth 默认的 AuthDefaultSource 和 开发者自定义的 AuthSource + AuthSource[] sources = this.concat(AuthDefaultSource.values(), extendSource); + // 筛选符合条件的 AuthSource + AuthSource source = Arrays.stream(sources).distinct() + .filter(authSource -> authSource.getName().equalsIgnoreCase(this.source)) + .findAny() + .orElseThrow(() -> new AuthException("未获取到有效的 AuthSource 配置")); + Class targetClass = source.getTargetClass(); + try { + if (this.authStateCache == null) { + return targetClass.getDeclaredConstructor(AuthConfig.class).newInstance(this.authConfig); + } else { + return targetClass.getDeclaredConstructor(AuthConfig.class, AuthStateCache.class).newInstance(this.authConfig, this.authStateCache); + } + } catch (Exception e) { + e.printStackTrace(); + throw new AuthException("未获取到有效的 Auth 配置"); + } + } + + private AuthSource[] concat(AuthSource[] first, AuthSource[] second) { + if (null == second || second.length == 0) { + return first; + } + AuthSource[] result = new AuthSource[first.length + second.length]; + System.arraycopy(first, 0, result, 0, first.length); + System.arraycopy(second, 0, result, first.length, second.length); + return result; + } + +} diff --git a/src/main/java/me/zhyd/oauth/config/AuthDefaultSource.java b/src/main/java/me/zhyd/oauth/config/AuthDefaultSource.java index fb750ac345904914335ddcd607ab0af1e97d2ccb..0711e268f4929b818055167bd1005a52273e6c84 100644 --- a/src/main/java/me/zhyd/oauth/config/AuthDefaultSource.java +++ b/src/main/java/me/zhyd/oauth/config/AuthDefaultSource.java @@ -1,12 +1,9 @@ package me.zhyd.oauth.config; -import me.zhyd.oauth.cache.AuthStateCache; import me.zhyd.oauth.enums.AuthResponseStatus; import me.zhyd.oauth.exception.AuthException; import me.zhyd.oauth.request.*; -import java.util.Arrays; - /** * JustAuth内置的各api需要的url, 用枚举类分平台类型管理 * @@ -17,7 +14,7 @@ public enum AuthDefaultSource implements AuthSource { /** * Github */ - GITHUB(AuthGithubRequest.class) { + GITHUB { @Override public String authorize() { return "https://github.com/login/oauth/authorize"; @@ -32,11 +29,16 @@ public enum AuthDefaultSource implements AuthSource { public String userInfo() { return "https://api.github.com/user"; } + + @Override + public Class getTargetClass() { + return AuthGithubRequest.class; + } }, /** * 新浪微博 */ - WEIBO(AuthWeiboRequest.class) { + WEIBO { @Override public String authorize() { return "https://api.weibo.com/oauth2/authorize"; @@ -56,11 +58,16 @@ public enum AuthDefaultSource implements AuthSource { public String revoke() { return "https://api.weibo.com/oauth2/revokeoauth2"; } + + @Override + public Class getTargetClass() { + return AuthWeiboRequest.class; + } }, /** * gitee */ - GITEE(AuthGiteeRequest.class) { + GITEE { @Override public String authorize() { return "https://gitee.com/oauth/authorize"; @@ -75,11 +82,16 @@ public enum AuthDefaultSource implements AuthSource { public String userInfo() { return "https://gitee.com/api/v5/user"; } + + @Override + public Class getTargetClass() { + return AuthGiteeRequest.class; + } }, /** * 钉钉扫码登录 */ - DINGTALK(AuthDingTalkRequest.class) { + DINGTALK { @Override public String authorize() { return "https://oapi.dingtalk.com/connect/qrconnect"; @@ -94,11 +106,16 @@ public enum AuthDefaultSource implements AuthSource { public String userInfo() { return "https://oapi.dingtalk.com/sns/getuserinfo_bycode"; } + + @Override + public Class getTargetClass() { + return AuthDingTalkRequest.class; + } }, /** * 钉钉账号登录 */ - DINGTALK_ACCOUNT(AuthDingTalkAccountRequest.class) { + DINGTALK_ACCOUNT { @Override public String authorize() { return "https://oapi.dingtalk.com/connect/oauth2/sns_authorize"; @@ -113,11 +130,16 @@ public enum AuthDefaultSource implements AuthSource { public String userInfo() { return DINGTALK.userInfo(); } + + @Override + public Class getTargetClass() { + return AuthDingTalkAccountRequest.class; + } }, /** * 百度 */ - BAIDU(AuthBaiduRequest.class) { + BAIDU { @Override public String authorize() { return "https://openapi.baidu.com/oauth/2.0/authorize"; @@ -142,11 +164,16 @@ public enum AuthDefaultSource implements AuthSource { public String refresh() { return "https://openapi.baidu.com/oauth/2.0/token"; } + + @Override + public Class getTargetClass() { + return AuthBaiduRequest.class; + } }, /** * csdn */ - CSDN(AuthCsdnRequest.class) { + CSDN { @Override public String authorize() { return "https://api.csdn.net/oauth2/authorize"; @@ -161,6 +188,11 @@ public enum AuthDefaultSource implements AuthSource { public String userInfo() { return "https://api.csdn.net/user/getinfo"; } + + @Override + public Class getTargetClass() { + return AuthCsdnRequest.class; + } }, /** * Coding, @@ -168,7 +200,7 @@ public enum AuthDefaultSource implements AuthSource { * 参考 https://help.coding.net/docs/project/open/oauth.html#%E7%94%A8%E6%88%B7%E6%8E%88%E6%9D%83 中的说明, * 新版的 coding API 地址需要传入用户团队名,这儿使用动态参数,方便在 request 中使用 */ - CODING(AuthCodingRequest.class) { + CODING { @Override public String authorize() { return "https://%s.coding.net/oauth_authorize.html"; @@ -183,11 +215,16 @@ public enum AuthDefaultSource implements AuthSource { public String userInfo() { return "https://%s.coding.net/api/account/current_user"; } + + @Override + public Class getTargetClass() { + return AuthCodingRequest.class; + } }, /** * oschina 开源中国 */ - OSCHINA(AuthOschinaRequest.class) { + OSCHINA { @Override public String authorize() { return "https://www.oschina.net/action/oauth2/authorize"; @@ -202,11 +239,16 @@ public enum AuthDefaultSource implements AuthSource { public String userInfo() { return "https://www.oschina.net/action/openapi/user"; } + + @Override + public Class getTargetClass() { + return AuthOschinaRequest.class; + } }, /** * 支付宝 */ - ALIPAY(AuthAlipayRequest.class) { + ALIPAY { @Override public String authorize() { return "https://openauth.alipay.com/oauth2/publicAppAuthorize.htm"; @@ -221,11 +263,16 @@ public enum AuthDefaultSource implements AuthSource { public String userInfo() { return "https://openapi.alipay.com/gateway.do"; } + + @Override + public Class getTargetClass() { + return AuthAlipayRequest.class; + } }, /** * QQ */ - QQ(AuthQqRequest.class) { + QQ { @Override public String authorize() { return "https://graph.qq.com/oauth2.0/authorize"; @@ -245,11 +292,16 @@ public enum AuthDefaultSource implements AuthSource { public String refresh() { return "https://graph.qq.com/oauth2.0/token"; } + + @Override + public Class getTargetClass() { + return AuthQqRequest.class; + } }, /** * 微信开放平台 */ - WECHAT_OPEN(AuthWeChatOpenRequest.class) { + WECHAT_OPEN { @Override public String authorize() { return "https://open.weixin.qq.com/connect/qrconnect"; @@ -269,11 +321,16 @@ public enum AuthDefaultSource implements AuthSource { public String refresh() { return "https://api.weixin.qq.com/sns/oauth2/refresh_token"; } + + @Override + public Class getTargetClass() { + return AuthWeChatOpenRequest.class; + } }, /** * 微信公众平台 */ - WECHAT_MP(AuthWeChatMpRequest.class) { + WECHAT_MP { @Override public String authorize() { return "https://open.weixin.qq.com/connect/oauth2/authorize"; @@ -293,11 +350,16 @@ public enum AuthDefaultSource implements AuthSource { public String refresh() { return "https://api.weixin.qq.com/sns/oauth2/refresh_token"; } + + @Override + public Class getTargetClass() { + return AuthWeChatMpRequest.class; + } }, /** * 淘宝 */ - TAOBAO(AuthTaobaoRequest.class) { + TAOBAO { @Override public String authorize() { return "https://oauth.taobao.com/authorize"; @@ -312,11 +374,16 @@ public enum AuthDefaultSource implements AuthSource { public String userInfo() { throw new AuthException(AuthResponseStatus.UNSUPPORTED); } + + @Override + public Class getTargetClass() { + return AuthTaobaoRequest.class; + } }, /** * Google */ - GOOGLE(AuthGoogleRequest.class) { + GOOGLE { @Override public String authorize() { return "https://accounts.google.com/o/oauth2/v2/auth"; @@ -331,11 +398,16 @@ public enum AuthDefaultSource implements AuthSource { public String userInfo() { return "https://www.googleapis.com/oauth2/v3/userinfo"; } + + @Override + public Class getTargetClass() { + return AuthGoogleRequest.class; + } }, /** * Facebook */ - FACEBOOK(AuthFacebookRequest.class) { + FACEBOOK { @Override public String authorize() { return "https://www.facebook.com/v10.0/dialog/oauth"; @@ -350,11 +422,16 @@ public enum AuthDefaultSource implements AuthSource { public String userInfo() { return "https://graph.facebook.com/v10.0/me"; } + + @Override + public Class getTargetClass() { + return AuthFacebookRequest.class; + } }, /** * 抖音 */ - DOUYIN(AuthDouyinRequest.class) { + DOUYIN { @Override public String authorize() { return "https://open.douyin.com/platform/oauth/connect"; @@ -374,11 +451,16 @@ public enum AuthDefaultSource implements AuthSource { public String refresh() { return "https://open.douyin.com/oauth/refresh_token/"; } + + @Override + public Class getTargetClass() { + return AuthDouyinRequest.class; + } }, /** * 领英 */ - LINKEDIN(AuthLinkedinRequest.class) { + LINKEDIN { @Override public String authorize() { return "https://www.linkedin.com/oauth/v2/authorization"; @@ -398,11 +480,16 @@ public enum AuthDefaultSource implements AuthSource { public String refresh() { return "https://www.linkedin.com/oauth/v2/accessToken"; } + + @Override + public Class getTargetClass() { + return AuthLinkedinRequest.class; + } }, /** * 微软 */ - MICROSOFT(AuthMicrosoftRequest.class) { + MICROSOFT { @Override public String authorize() { return "https://login.microsoftonline.com/common/oauth2/v2.0/authorize"; @@ -422,11 +509,16 @@ public enum AuthDefaultSource implements AuthSource { public String refresh() { return "https://login.microsoftonline.com/common/oauth2/v2.0/token"; } + + @Override + public Class getTargetClass() { + return AuthMicrosoftRequest.class; + } }, /** * 小米 */ - MI(AuthMiRequest.class) { + MI { @Override public String authorize() { return "https://account.xiaomi.com/oauth2/authorize"; @@ -446,11 +538,16 @@ public enum AuthDefaultSource implements AuthSource { public String refresh() { return "https://account.xiaomi.com/oauth2/token"; } + + @Override + public Class getTargetClass() { + return AuthMiRequest.class; + } }, /** * 今日头条 */ - TOUTIAO(AuthToutiaoRequest.class) { + TOUTIAO { @Override public String authorize() { return "https://open.snssdk.com/auth/authorize"; @@ -465,11 +562,16 @@ public enum AuthDefaultSource implements AuthSource { public String userInfo() { return "https://open.snssdk.com/data/user_profile"; } + + @Override + public Class getTargetClass() { + return AuthToutiaoRequest.class; + } }, /** * Teambition */ - TEAMBITION(AuthTeambitionRequest.class) { + TEAMBITION { @Override public String authorize() { return "https://account.teambition.com/oauth2/authorize"; @@ -489,12 +591,17 @@ public enum AuthDefaultSource implements AuthSource { public String userInfo() { return "https://api.teambition.com/users/me"; } + + @Override + public Class getTargetClass() { + return AuthTeambitionRequest.class; + } }, /** * 人人网 */ - RENREN(AuthRenrenRequest.class) { + RENREN { @Override public String authorize() { return "https://graph.renren.com/oauth/authorize"; @@ -514,12 +621,17 @@ public enum AuthDefaultSource implements AuthSource { public String userInfo() { return "https://api.renren.com/v2/user/get"; } + + @Override + public Class getTargetClass() { + return AuthRenrenRequest.class; + } }, /** * Pinterest */ - PINTEREST(AuthPinterestRequest.class) { + PINTEREST { @Override public String authorize() { return "https://api.pinterest.com/oauth"; @@ -534,12 +646,17 @@ public enum AuthDefaultSource implements AuthSource { public String userInfo() { return "https://api.pinterest.com/v1/me"; } + + @Override + public Class getTargetClass() { + return AuthPinterestRequest.class; + } }, /** * Stack Overflow */ - STACK_OVERFLOW(AuthStackOverflowRequest.class) { + STACK_OVERFLOW { @Override public String authorize() { return "https://stackoverflow.com/oauth"; @@ -554,6 +671,11 @@ public enum AuthDefaultSource implements AuthSource { public String userInfo() { return "https://api.stackexchange.com/2.2/me"; } + + @Override + public Class getTargetClass() { + return AuthStackOverflowRequest.class; + } }, /** @@ -561,7 +683,7 @@ public enum AuthDefaultSource implements AuthSource { * * @since 1.10.0 */ - HUAWEI(AuthHuaweiRequest.class) { + HUAWEI { @Override public String authorize() { return "https://oauth-login.cloud.huawei.com/oauth2/v2/authorize"; @@ -581,6 +703,11 @@ public enum AuthDefaultSource implements AuthSource { public String refresh() { return "https://oauth-login.cloud.huawei.com/oauth2/v2/token"; } + + @Override + public Class getTargetClass() { + return AuthHuaweiRequest.class; + } }, /** @@ -588,7 +715,7 @@ public enum AuthDefaultSource implements AuthSource { * * @since 1.10.0 */ - WECHAT_ENTERPRISE(AuthWeChatEnterpriseQrcodeRequest.class) { + WECHAT_ENTERPRISE { @Override public String authorize() { return "https://open.work.weixin.qq.com/wwopen/sso/qrConnect"; @@ -603,12 +730,17 @@ public enum AuthDefaultSource implements AuthSource { public String userInfo() { return "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo"; } + + @Override + public Class getTargetClass() { + return AuthWeChatEnterpriseQrcodeRequest.class; + } }, /** * 企业微信网页登录 */ - WECHAT_ENTERPRISE_WEB(AuthWeChatEnterpriseWebRequest.class) { + WECHAT_ENTERPRISE_WEB { @Override public String authorize() { return "https://open.weixin.qq.com/connect/oauth2/authorize"; @@ -623,6 +755,11 @@ public enum AuthDefaultSource implements AuthSource { public String userInfo() { return "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo"; } + + @Override + public Class getTargetClass() { + return AuthWeChatEnterpriseWebRequest.class; + } }, /** @@ -630,7 +767,7 @@ public enum AuthDefaultSource implements AuthSource { * * @since 1.11.0 */ - KUJIALE(AuthKujialeRequest.class) { + KUJIALE { @Override public String authorize() { return "https://oauth.kujiale.com/oauth2/show"; @@ -650,6 +787,11 @@ public enum AuthDefaultSource implements AuthSource { public String refresh() { return "https://oauth.kujiale.com/oauth2/auth/token/refresh"; } + + @Override + public Class getTargetClass() { + return AuthKujialeRequest.class; + } }, /** @@ -657,7 +799,7 @@ public enum AuthDefaultSource implements AuthSource { * * @since 1.11.0 */ - GITLAB(AuthGitlabRequest.class) { + GITLAB { @Override public String authorize() { return "https://gitlab.com/oauth/authorize"; @@ -672,6 +814,11 @@ public enum AuthDefaultSource implements AuthSource { public String userInfo() { return "https://gitlab.com/api/v4/user"; } + + @Override + public Class getTargetClass() { + return AuthGitlabRequest.class; + } }, /** @@ -679,7 +826,7 @@ public enum AuthDefaultSource implements AuthSource { * * @since 1.12.0 */ - MEITUAN(AuthMeituanRequest.class) { + MEITUAN { @Override public String authorize() { return "https://openapi.waimai.meituan.com/oauth/authorize"; @@ -699,6 +846,11 @@ public enum AuthDefaultSource implements AuthSource { public String refresh() { return "https://openapi.waimai.meituan.com/oauth/refresh_token"; } + + @Override + public Class getTargetClass() { + return AuthMeituanRequest.class; + } }, /** @@ -708,7 +860,7 @@ public enum AuthDefaultSource implements AuthSource { * * @since 1.12.0 */ - ELEME(AuthElemeRequest.class) { + ELEME { @Override public String authorize() { return "https://open-api.shop.ele.me/authorize"; @@ -728,6 +880,11 @@ public enum AuthDefaultSource implements AuthSource { public String refresh() { return "https://open-api.shop.ele.me/token"; } + + @Override + public Class getTargetClass() { + return AuthElemeRequest.class; + } }, /** @@ -735,7 +892,7 @@ public enum AuthDefaultSource implements AuthSource { * * @since 1.13.0 */ - TWITTER(AuthTwitterRequest.class) { + TWITTER { @Override public String authorize() { return "https://api.twitter.com/oauth/authenticate"; @@ -750,6 +907,11 @@ public enum AuthDefaultSource implements AuthSource { public String userInfo() { return "https://api.twitter.com/1.1/account/verify_credentials.json"; } + + @Override + public Class getTargetClass() { + return AuthTwitterRequest.class; + } }, /** @@ -759,7 +921,7 @@ public enum AuthDefaultSource implements AuthSource { * * @since 1.15.9 */ - FEISHU(AuthFeishuRequest.class) { + FEISHU { @Override public String authorize() { return "https://open.feishu.cn/open-apis/authen/v1/index"; @@ -779,13 +941,18 @@ public enum AuthDefaultSource implements AuthSource { public String refresh() { return "https://open.feishu.cn/open-apis/authen/v1/refresh_access_token"; } + + @Override + public Class getTargetClass() { + return AuthFeishuRequest.class; + } }, /** * 京东 * * @since 1.15.0 */ - JD(AuthJdRequest.class) { + JD { @Override public String authorize() { return "https://open-oauth.jd.com/oauth2/to_login"; @@ -805,12 +972,17 @@ public enum AuthDefaultSource implements AuthSource { public String refresh() { return "https://open-oauth.jd.com/oauth2/refresh_token"; } + + @Override + public Class getTargetClass() { + return AuthJdRequest.class; + } }, /** * 阿里云 */ - ALIYUN(AuthAliyunRequest.class) { + ALIYUN { @Override public String authorize() { return "https://signin.aliyun.com/oauth2/v1/auth"; @@ -830,12 +1002,17 @@ public enum AuthDefaultSource implements AuthSource { public String refresh() { return "https://oauth.aliyun.com/v1/token"; } + + @Override + public Class getTargetClass() { + return AuthAliyunRequest.class; + } }, /** * 喜马拉雅 */ - XMLY(AuthXmlyRequest.class) { + XMLY { @Override public String authorize() { return "https://api.ximalaya.com/oauth2/js/authorize"; @@ -855,6 +1032,11 @@ public enum AuthDefaultSource implements AuthSource { public String refresh() { return "https://oauth.aliyun.com/v1/token"; } + + @Override + public Class getTargetClass() { + return AuthXmlyRequest.class; + } }, /** @@ -862,7 +1044,7 @@ public enum AuthDefaultSource implements AuthSource { * * @since 1.16.0 */ - AMAZON(AuthAmazonRequest.class) { + AMAZON { @Override public String authorize() { return "https://www.amazon.com/ap/oa"; @@ -882,13 +1064,18 @@ public enum AuthDefaultSource implements AuthSource { public String refresh() { return "https://api.amazon.com/auth/o2/token"; } + + @Override + public Class getTargetClass() { + return AuthAmazonRequest.class; + } }, /** * Slack * * @since 1.16.0 */ - SLACK(AuthSlackRequest.class) { + SLACK { @Override public String authorize() { return "https://slack.com/oauth/v2/authorize"; @@ -915,13 +1102,18 @@ public enum AuthDefaultSource implements AuthSource { public String revoke() { return "https://slack.com/api/auth.revoke"; } + + @Override + public Class getTargetClass() { + return AuthSlackRequest.class; + } }, /** * line * * @since 1.16.0 */ - LINE(AuthLineRequest.class) { + LINE { @Override public String authorize() { return "https://access.line.me/oauth2/v2.1/authorize"; @@ -946,6 +1138,11 @@ public enum AuthDefaultSource implements AuthSource { public String revoke() { return "https://api.line.me/oauth2/v2.1/revoke"; } + + @Override + public Class getTargetClass() { + return AuthLineRequest.class; + } }, /** * Okta, @@ -954,7 +1151,7 @@ public enum AuthDefaultSource implements AuthSource { * * @since 1.16.0 */ - OKTA(AuthOktaRequest.class) { + OKTA { @Override public String authorize() { return "https://%s.okta.com/oauth2/%s/v1/authorize"; @@ -979,13 +1176,18 @@ public enum AuthDefaultSource implements AuthSource { public String revoke() { return "https://%s.okta.com/oauth2/%s/v1/revoke"; } + + @Override + public Class getTargetClass() { + return AuthOktaRequest.class; + } }, /** * 程序员客栈 * * @since 1.16.2 */ - PROGINN(AuthProginnRequest.class) { + PROGINN { @Override public String authorize() { return "https://www.proginn.com/oauth2/authorize"; @@ -1000,48 +1202,10 @@ public enum AuthDefaultSource implements AuthSource { public String userInfo() { return "https://www.proginn.com/openapi/user/basic_info"; } - }; - /** 对应的实现类 */ - private Class targetClass; - - AuthDefaultSource(Class targetClass) { - this.targetClass = targetClass; - } - - /** - * 根据source获取对应的AuthSource枚举 - * @param source 枚举名 - * @return AuthDefaultSource - */ - public static AuthDefaultSource getAuthSource(String source){ - return Arrays.stream(AuthDefaultSource.values()).filter(authSource -> authSource.name().equalsIgnoreCase(source)).findAny().orElseThrow(()->new AuthException("未获取到有效的AuthSource配置")); - } - - /** - * 根据配置获取 AuthRequest 实例 - * @param authConfig 配置 - * @return AuthRequest - */ - public AuthRequest getAuthRequestInstance(AuthConfig authConfig) { - return getAuthRequestInstance(authConfig,null); - } - - /** - * 利用反射 生成 AuthRequest 实例 - * @param authConfig 配置 - * @param authStateCache 缓存配置 - * @return AuthRequest - */ - public AuthRequest getAuthRequestInstance(AuthConfig authConfig, AuthStateCache authStateCache) { - try { - if(authStateCache==null){ - return this.targetClass.getDeclaredConstructor(AuthConfig.class).newInstance(authConfig); - }else{ - return this.targetClass.getDeclaredConstructor(AuthConfig.class, AuthStateCache.class).newInstance(authConfig, authStateCache); - } - } catch (Exception e) { - throw new AuthException("未获取到有效的Auth配置"); + @Override + public Class getTargetClass() { + return AuthProginnRequest.class; } } diff --git a/src/main/java/me/zhyd/oauth/config/AuthSource.java b/src/main/java/me/zhyd/oauth/config/AuthSource.java index a6cde6460d2e6f2a429cc26110a09de9a0ed9b15..c7be23f49b96030ffd97fc99bcf2dc91bbd93a93 100644 --- a/src/main/java/me/zhyd/oauth/config/AuthSource.java +++ b/src/main/java/me/zhyd/oauth/config/AuthSource.java @@ -3,6 +3,7 @@ package me.zhyd.oauth.config; import me.zhyd.oauth.enums.AuthResponseStatus; import me.zhyd.oauth.exception.AuthException; import me.zhyd.oauth.model.AuthCallback; +import me.zhyd.oauth.request.AuthDefaultRequest; /** * OAuth平台的API地址的统一接口,提供以下方法: @@ -73,4 +74,11 @@ public interface AuthSource { } return this.getClass().getSimpleName(); } + + /** + * 平台对应的 AuthRequest 实现类,必须继承自 {@link AuthDefaultRequest} + * + * @return class + */ + Class getTargetClass(); } diff --git a/src/test/java/me/zhyd/oauth/AuthRequestBuilderTest.java b/src/test/java/me/zhyd/oauth/AuthRequestBuilderTest.java new file mode 100644 index 0000000000000000000000000000000000000000..253e365791501db148626ab1625360a73c8fea32 --- /dev/null +++ b/src/test/java/me/zhyd/oauth/AuthRequestBuilderTest.java @@ -0,0 +1,105 @@ +package me.zhyd.oauth; + +import me.zhyd.oauth.config.AuthConfig; +import me.zhyd.oauth.config.AuthDefaultSource; +import me.zhyd.oauth.config.AuthExtendSource; +import me.zhyd.oauth.request.AuthExtendRequest; +import me.zhyd.oauth.request.AuthGiteeRequest; +import me.zhyd.oauth.request.AuthGithubRequest; +import me.zhyd.oauth.request.AuthRequest; +import me.zhyd.oauth.utils.AuthStateUtils; +import org.junit.Assert; +import org.junit.Test; + +public class AuthRequestBuilderTest { + + /** + * 示例:一般场景下通过 AuthRequestBuilder 构建 AuthRequest + */ + @Test + public void build2() { + AuthRequest authRequest = AuthRequestBuilder.builder() + .source("github") + .authConfig(AuthConfig.builder() + .clientId("a") + .clientSecret("a") + .redirectUri("https://www.justauth.cn") + .build()) + .build(); + Assert.assertTrue(authRequest instanceof AuthGithubRequest); + System.out.println(authRequest.authorize(AuthStateUtils.createState())); + } + + /** + * 示例:AuthConfig 需要动态获取的场景下通过 AuthRequestBuilder 构建 AuthRequest + */ + @Test + public void build() { + AuthRequest authRequest = AuthRequestBuilder.builder() + .source("gitee") + .authConfig((source) -> { + // 通过 source 动态获取 AuthConfig + // 此处可以灵活的从 sql 中取配置也可以从配置文件中取配置 + return AuthConfig.builder() + .clientId(source) + .clientSecret(source) + .redirectUri("https://www.justauth.cn/" + source) + .build(); + }) + .build(); + Assert.assertTrue(authRequest instanceof AuthGiteeRequest); + System.out.println(authRequest.authorize(AuthStateUtils.createState())); + } + + /** + * 示例:自定义实现的 AuthRequest,通过 AuthRequestBuilder 构建 AuthRequest + */ + @Test + public void build3() { + AuthRequest authRequest = AuthRequestBuilder.builder() + // 关键点:将自定义的 AuthSource 配置上 + .extendSource(AuthExtendSource.values()) + .source("other") + .authConfig(AuthConfig.builder() + .clientId("a") + .clientSecret("a") + .redirectUri("https://www.justauth.cn") + .build()) + .build(); + Assert.assertTrue(authRequest instanceof AuthExtendRequest); + System.out.println(authRequest.authorize(AuthStateUtils.createState())); + } + + /** + * 测试不同平台 + */ + @Test + public void build4() { + for (AuthDefaultSource value : AuthDefaultSource.values()) { + if (value == AuthDefaultSource.TWITTER) { + System.out.println(value.getTargetClass()); + System.out.println("忽略 twitter"); + continue; + } + AuthRequest authRequest = AuthRequestBuilder.builder() + .source(value.getName()) + .authConfig(AuthConfig.builder() + .clientId("a") + .clientSecret("a") + .redirectUri("https://www.justauth.cn") + .alipayPublicKey("asd") + .authServerId("asd") + .agentId("asd") + .domainPrefix("asd") + .stackOverflowKey("asd") + + .deviceId("asd") + .clientOsType(3) + .build()) + .build(); + System.out.println(value.getTargetClass()); + System.out.println(authRequest.authorize(AuthStateUtils.createState())); + } + + } +} diff --git a/src/test/java/me/zhyd/oauth/config/AuthExtendSource.java b/src/test/java/me/zhyd/oauth/config/AuthExtendSource.java index 9f57097a717fcaf4fc6a7c223ea7fb941f594735..c1262bb536777ad1f565f3681d377c0bab8d82a3 100644 --- a/src/test/java/me/zhyd/oauth/config/AuthExtendSource.java +++ b/src/test/java/me/zhyd/oauth/config/AuthExtendSource.java @@ -1,10 +1,7 @@ package me.zhyd.oauth.config; -import me.zhyd.oauth.cache.AuthStateCache; -import me.zhyd.oauth.exception.AuthException; import me.zhyd.oauth.request.AuthDefaultRequest; import me.zhyd.oauth.request.AuthExtendRequest; -import me.zhyd.oauth.request.AuthRequest; /** * 测试自定义实现{@link AuthSource}接口后的枚举类 @@ -15,7 +12,7 @@ import me.zhyd.oauth.request.AuthRequest; */ public enum AuthExtendSource implements AuthSource { - OTHER (AuthExtendRequest.class){ + OTHER { /** * 授权的api * @@ -65,27 +62,10 @@ public enum AuthExtendSource implements AuthSource { public String refresh() { return null; } - }; - private Class targetClass; - - AuthExtendSource(Class targetClass) { - this.targetClass = targetClass; - } - - public AuthRequest getAuthRequestInstance(AuthConfig authConfig) { - return this.getAuthRequestInstance(authConfig,null); - } - - public AuthRequest getAuthRequestInstance(AuthConfig authConfig, AuthStateCache authStateCache) { - try { - if(authStateCache==null){ - return this.targetClass.getDeclaredConstructor(AuthConfig.class).newInstance(authConfig); - }else{ - return this.targetClass.getDeclaredConstructor(AuthConfig.class, AuthStateCache.class).newInstance(authConfig, authStateCache); - } - } catch (Exception e) { - throw new AuthException("未获取到有效的Auth配置"); + @Override + public Class getTargetClass() { + return AuthExtendRequest.class; } } diff --git a/src/test/java/me/zhyd/oauth/request/AuthWeChatMpRequestTest.java b/src/test/java/me/zhyd/oauth/request/AuthWeChatMpRequestTest.java index c820d8fcec9891f0ba3c22913c3710099a3ab959..1fd144af8f790b21b02e4a360bf397e1d30ee482 100644 --- a/src/test/java/me/zhyd/oauth/request/AuthWeChatMpRequestTest.java +++ b/src/test/java/me/zhyd/oauth/request/AuthWeChatMpRequestTest.java @@ -1,9 +1,7 @@ package me.zhyd.oauth.request; import me.zhyd.oauth.config.AuthConfig; -import me.zhyd.oauth.config.AuthDefaultSource; import me.zhyd.oauth.utils.AuthStateUtils; -import org.junit.Assert; import org.junit.Test; public class AuthWeChatMpRequestTest { @@ -18,15 +16,4 @@ public class AuthWeChatMpRequestTest { .build()); System.out.println(request.authorize(AuthStateUtils.createState())); } - - @Test - public void authorize1() { - AuthRequest request = AuthDefaultSource.getAuthSource("wechat_mp").getAuthRequestInstance(AuthConfig.builder() - .clientId("a") - .clientSecret("a") - .redirectUri("https://www.justauth.cn") - .build()); - Assert.assertTrue(request instanceof AuthWeChatMpRequest); - System.out.println(request.authorize(AuthStateUtils.createState())); - } }