From 7892f7e5474242ea28511aa8151c08811e70da0d Mon Sep 17 00:00:00 2001 From: "yadong.zhang" Date: Sat, 23 Feb 2019 16:44:06 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20=E6=94=AF=E6=8C=81Coding=E3=80=81C?= =?UTF-8?q?sdn=E5=92=8COSChina?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 10 +- pom.xml | 6 + .../me/zhyd/oauth/consts/ApiUrlConst.java | 45 +++++++ .../java/me/zhyd/oauth/model/AuthSource.java | 4 + .../zhyd/oauth/request/AuthCodingRequest.java | 58 +++++++++ .../zhyd/oauth/request/AuthCsdnRequest.java | 49 ++++++++ .../oauth/request/AuthDingTalkRequest.java | 5 + .../oauth/request/AuthOschinaRequest.java | 56 +++++++++ .../me/zhyd/oauth/request/AuthRequest.java | 9 ++ .../zhyd/oauth/request/AuthWeiboRequest.java | 2 +- .../zhyd/oauth/request/BaseAuthRequest.java | 10 +- .../java/me/zhyd/oauth/utils/UrlBuilder.java | 113 ++++++++++++++++++ 12 files changed, 361 insertions(+), 6 deletions(-) create mode 100644 src/main/java/me/zhyd/oauth/request/AuthCodingRequest.java create mode 100644 src/main/java/me/zhyd/oauth/request/AuthCsdnRequest.java create mode 100644 src/main/java/me/zhyd/oauth/request/AuthOschinaRequest.java diff --git a/README.md b/README.md index d71e1c2..e9c24c9 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,10 @@ - + + + @@ -38,6 +40,8 @@ 钉钉 百度 CSDN + Coding + OSChina QQ 微信 @@ -83,7 +87,9 @@ authRequest.login("code"); | | [AuthWeiboRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthGiteeRequest.java) | 参考文档 | | | [AuthDingTalkRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthDingTalkRequest.java) | 参考文档 | | | [AuthBaiduRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthBaiduRequest.java) | 参考文档 | -| | AuthCsdnRequest | 待续 | +| | [AuthCsdnRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthCsdnRequest.java) | 待续 | +| | [AuthCodingRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthCodingRequest.java) | 参考文档 | +| | [AuthOschinaRequest](https://gitee.com/yadong.zhang/JustAuth/blob/master/src/main/java/me/zhyd/oauth/request/AuthOschinaRequest.java) | 参考文档 | | | AuthQqRequest | 参考文档 | | | AuthWechatRequest | 待续 | diff --git a/pom.xml b/pom.xml index acce7b1..0928f24 100644 --- a/pom.xml +++ b/pom.xml @@ -45,6 +45,7 @@ 4.11 2.5 1.2.44 + 1.28.0 @@ -74,6 +75,11 @@ fastjson ${fastjson-version} + + com.google.api-client + google-api-client + ${google-api-version} + diff --git a/src/main/java/me/zhyd/oauth/consts/ApiUrlConst.java b/src/main/java/me/zhyd/oauth/consts/ApiUrlConst.java index 82ff825..5baed22 100644 --- a/src/main/java/me/zhyd/oauth/consts/ApiUrlConst.java +++ b/src/main/java/me/zhyd/oauth/consts/ApiUrlConst.java @@ -86,4 +86,49 @@ public class ApiUrlConst { */ public static final String BAIDU_REVOKE_URL = "https://openapi.baidu.com/rest/2.0/passport/auth/revokeAuthorization"; + /** + * 获取csdn access_token的地址 + */ + public static final String CSDN_ACCESS_TOKEN_URL = "https://api.csdn.net/oauth2/access_token"; + + /** + * 获取csdn用户信息的地址 + */ + public static final String CSDN_USER_INFO_URL = "https://api.csdn.net/user/getinfo"; + + /** + * 获取csdn授权地址 + */ + public static final String CSDN_AUTHORIZE_URL = "https://api.csdn.net/oauth2/authorize"; + + /** + * 获取coding access_token的地址 + */ + public static final String CODING_ACCESS_TOKEN_URL = "https://coding.net/api/oauth/access_token"; + + /** + * 获取coding用户信息的地址 + */ + public static final String CODING_USER_INFO_URL = "https://coding.net/api/account/current_user"; + + /** + * 获取coding授权地址 + */ + public static final String CODING_AUTHORIZE_URL = "https://coding.net/oauth_authorize.html"; + + /** + * 获取oschina access_token的地址 + */ + public static final String OSCHINA_ACCESS_TOKEN_URL = "https://www.oschina.net/action/openapi/token"; + + /** + * 获取oschina用户信息的地址 + */ + public static final String OSCHINA_USER_INFO_URL = "https://www.oschina.net/action/openapi/user"; + + /** + * 获取oschina授权地址 + */ + public static final String OSCHINA_AUTHORIZE_URL = "https://www.oschina.net/action/oauth2/authorize"; + } diff --git a/src/main/java/me/zhyd/oauth/model/AuthSource.java b/src/main/java/me/zhyd/oauth/model/AuthSource.java index 5dac4ab..b501ebb 100644 --- a/src/main/java/me/zhyd/oauth/model/AuthSource.java +++ b/src/main/java/me/zhyd/oauth/model/AuthSource.java @@ -13,6 +13,10 @@ public enum AuthSource { WEIBO, DINGTALK, BAIDU, + CSDN, + CODING, + OSCHINA, + QQ, WECHAT, GOOGLE, diff --git a/src/main/java/me/zhyd/oauth/request/AuthCodingRequest.java b/src/main/java/me/zhyd/oauth/request/AuthCodingRequest.java new file mode 100644 index 0000000..3fa1e7a --- /dev/null +++ b/src/main/java/me/zhyd/oauth/request/AuthCodingRequest.java @@ -0,0 +1,58 @@ +package me.zhyd.oauth.request; + +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import com.alibaba.fastjson.JSONObject; +import me.zhyd.oauth.config.AuthConfig; +import me.zhyd.oauth.exception.AuthException; +import me.zhyd.oauth.model.AuthSource; +import me.zhyd.oauth.model.AuthUser; +import me.zhyd.oauth.model.AuthUserGender; +import me.zhyd.oauth.utils.UrlBuilder; + +/** + * @author yadong.zhang (yadong.zhang0415(a)gmail.com) + * @version 1.0 + * @website https://www.zhyd.me + * @date 2019/2/23 15:48 + * @since 1.8 + */ +public class AuthCodingRequest extends BaseAuthRequest { + + public AuthCodingRequest(AuthConfig config) { + super(config, AuthSource.CODING); + } + + @Override + protected String getAccessToken(String code) { + String accessTokenUrl = UrlBuilder.getCodingAccessTokenUrl(config.getClientId(), config.getClientSecret(), code); + HttpResponse response = HttpRequest.post(accessTokenUrl).execute(); + JSONObject accessTokenObject = JSONObject.parseObject(response.body()); + if (accessTokenObject.getIntValue("code") != 0) { + throw new AuthException("Unable to get token from coding using code [" + code + "]"); + } + return accessTokenObject.getString("access_token"); + } + + @Override + protected AuthUser getUserInfo(String accessToken) { + HttpResponse response = HttpRequest.get(UrlBuilder.getCodingUserInfoUrl(accessToken)).execute(); + JSONObject object = JSONObject.parseObject(response.body()); + if (object.getIntValue("code") != 0) { + throw new AuthException(object.getString("msg")); + } + return AuthUser.builder() + .username(object.getString("name")) + .avatar(object.getString("avatar")) + .blog("https://coding.net/" + object.getString("path")) + .nickname(object.getString("name")) + .company(object.getString("company")) + .location(object.getString("location")) + .gender(AuthUserGender.getRealGender(object.getString("sex"))) + .email(object.getString("email")) + .remark(object.getString("slogan")) + .accessToken(accessToken) + .source(AuthSource.CODING) + .build(); + } +} diff --git a/src/main/java/me/zhyd/oauth/request/AuthCsdnRequest.java b/src/main/java/me/zhyd/oauth/request/AuthCsdnRequest.java new file mode 100644 index 0000000..5bafe93 --- /dev/null +++ b/src/main/java/me/zhyd/oauth/request/AuthCsdnRequest.java @@ -0,0 +1,49 @@ +package me.zhyd.oauth.request; + +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import com.alibaba.fastjson.JSONObject; +import me.zhyd.oauth.config.AuthConfig; +import me.zhyd.oauth.exception.AuthException; +import me.zhyd.oauth.model.AuthSource; +import me.zhyd.oauth.model.AuthUser; +import me.zhyd.oauth.utils.UrlBuilder; + +/** + * @author yadong.zhang (yadong.zhang0415(a)gmail.com) + * @version 1.0 + * @website https://www.zhyd.me + * @date 2019/2/23 15:00 + * @since 1.8 + */ +public class AuthCsdnRequest extends BaseAuthRequest { + + public AuthCsdnRequest(AuthConfig config) { + super(config, AuthSource.CSDN); + } + + @Override + protected String getAccessToken(String code) { + String accessTokenUrl = UrlBuilder.getCsdnAccessTokenUrl(config.getClientId(), config.getClientSecret(), code, config.getRedirectUri()); + HttpResponse response = HttpRequest.post(accessTokenUrl).execute(); + JSONObject accessTokenObject = JSONObject.parseObject(response.body()); + if (accessTokenObject.containsKey("error_code")) { + throw new AuthException("Unable to get token from csdn using code [" + code + "]"); + } + return accessTokenObject.getString("access_token"); + } + + @Override + protected AuthUser getUserInfo(String accessToken) { + HttpResponse response = HttpRequest.get(UrlBuilder.getCsdnUserInfoUrl(accessToken)).execute(); + JSONObject object = JSONObject.parseObject(response.body()); + if (object.containsKey("error_code")) { + throw new AuthException(object.getString("error")); + } + return AuthUser.builder() + .username(object.getString("username")) + .accessToken(accessToken) + .source(AuthSource.CSDN) + .build(); + } +} diff --git a/src/main/java/me/zhyd/oauth/request/AuthDingTalkRequest.java b/src/main/java/me/zhyd/oauth/request/AuthDingTalkRequest.java index 06c25e7..14962d5 100644 --- a/src/main/java/me/zhyd/oauth/request/AuthDingTalkRequest.java +++ b/src/main/java/me/zhyd/oauth/request/AuthDingTalkRequest.java @@ -27,6 +27,11 @@ public class AuthDingTalkRequest extends BaseAuthRequest { super(config, AuthSource.DINGTALK); } + @Override + protected String getAccessToken(String code) { + throw new AuthException(ResponseStatus.NOT_IMPLEMENTED); + } + @Override protected AuthUser getUserInfo(String code) { // 根据timestamp, appSecret计算签名值 diff --git a/src/main/java/me/zhyd/oauth/request/AuthOschinaRequest.java b/src/main/java/me/zhyd/oauth/request/AuthOschinaRequest.java new file mode 100644 index 0000000..084e41f --- /dev/null +++ b/src/main/java/me/zhyd/oauth/request/AuthOschinaRequest.java @@ -0,0 +1,56 @@ +package me.zhyd.oauth.request; + +import cn.hutool.http.HttpRequest; +import cn.hutool.http.HttpResponse; +import com.alibaba.fastjson.JSONObject; +import me.zhyd.oauth.config.AuthConfig; +import me.zhyd.oauth.exception.AuthException; +import me.zhyd.oauth.model.AuthSource; +import me.zhyd.oauth.model.AuthUser; +import me.zhyd.oauth.model.AuthUserGender; +import me.zhyd.oauth.utils.UrlBuilder; + +/** + * @author yadong.zhang (yadong.zhang0415(a)gmail.com) + * @version 1.0 + * @website https://www.zhyd.me + * @date 2019/2/23 15:48 + * @since 1.8 + */ +public class AuthOschinaRequest extends BaseAuthRequest { + + public AuthOschinaRequest(AuthConfig config) { + super(config, AuthSource.OSCHINA); + } + + @Override + protected String getAccessToken(String code) { + String accessTokenUrl = UrlBuilder.getOschinaAccessTokenUrl(config.getClientId(), config.getClientSecret(), code, config.getRedirectUri()); + HttpResponse response = HttpRequest.post(accessTokenUrl).execute(); + JSONObject accessTokenObject = JSONObject.parseObject(response.body()); + if (accessTokenObject.containsKey("error")) { + throw new AuthException("Unable to get token from oschina using code [" + code + "]"); + } + return accessTokenObject.getString("access_token"); + } + + @Override + protected AuthUser getUserInfo(String accessToken) { + HttpResponse response = HttpRequest.get(UrlBuilder.getOschinaUserInfoUrl(accessToken)).execute(); + JSONObject object = JSONObject.parseObject(response.body()); + if (object.containsKey("error")) { + throw new AuthException(object.getString("error_description")); + } + return AuthUser.builder() + .username(object.getString("name")) + .nickname(object.getString("name")) + .avatar(object.getString("avatar")) + .blog(object.getString("url")) + .location(object.getString("location")) + .gender(AuthUserGender.getRealGender(object.getString("gender"))) + .email(object.getString("email")) + .accessToken(accessToken) + .source(AuthSource.OSCHINA) + .build(); + } +} diff --git a/src/main/java/me/zhyd/oauth/request/AuthRequest.java b/src/main/java/me/zhyd/oauth/request/AuthRequest.java index f82948f..6f3b6fc 100644 --- a/src/main/java/me/zhyd/oauth/request/AuthRequest.java +++ b/src/main/java/me/zhyd/oauth/request/AuthRequest.java @@ -49,4 +49,13 @@ public interface AuthRequest { default AuthResponse revoke(String accessToken) { throw new AuthException(ResponseStatus.NOT_IMPLEMENTED); } + + /** + * 刷新access token (续期) + * + * @param accessToken 登录成功后返回的accessToken + */ + default AuthResponse refresh(String accessToken) { + throw new AuthException(ResponseStatus.NOT_IMPLEMENTED); + } } diff --git a/src/main/java/me/zhyd/oauth/request/AuthWeiboRequest.java b/src/main/java/me/zhyd/oauth/request/AuthWeiboRequest.java index 90388f9..7ef35d7 100644 --- a/src/main/java/me/zhyd/oauth/request/AuthWeiboRequest.java +++ b/src/main/java/me/zhyd/oauth/request/AuthWeiboRequest.java @@ -59,7 +59,7 @@ public class AuthWeiboRequest extends BaseAuthRequest { .location(object.getString("location")) .remark(object.getString("description")) .gender(AuthUserGender.getRealGender(object.getString("gender"))) - .accessToken(GlobalAuthUtil.parseStringToMap(accessToken).get("access_token=")) + .accessToken(GlobalAuthUtil.parseStringToMap(accessToken).get("access_token")) .source(AuthSource.WEIBO) .build(); } diff --git a/src/main/java/me/zhyd/oauth/request/BaseAuthRequest.java b/src/main/java/me/zhyd/oauth/request/BaseAuthRequest.java index aa2c51e..e7f6bf7 100644 --- a/src/main/java/me/zhyd/oauth/request/BaseAuthRequest.java +++ b/src/main/java/me/zhyd/oauth/request/BaseAuthRequest.java @@ -32,9 +32,7 @@ public abstract class BaseAuthRequest implements AuthRequest { } } - protected String getAccessToken(String code) { - return null; - } + protected abstract String getAccessToken(String code); protected abstract AuthUser getUserInfo(String accessToken); @@ -69,6 +67,12 @@ public abstract class BaseAuthRequest implements AuthRequest { case GITHUB: authorizeUrl = UrlBuilder.getGithubAuthorizeUrl(config.getClientId(), config.getRedirectUri()); break; + case CSDN: + authorizeUrl = UrlBuilder.getCsdnAuthorizeUrl(config.getClientId(), config.getRedirectUri()); + break; + case CODING: + authorizeUrl = UrlBuilder.getCodingAuthorizeUrl(config.getClientId(), config.getRedirectUri()); + break; case QQ: break; case WECHAT: diff --git a/src/main/java/me/zhyd/oauth/utils/UrlBuilder.java b/src/main/java/me/zhyd/oauth/utils/UrlBuilder.java index dea7f4f..83a7f1d 100644 --- a/src/main/java/me/zhyd/oauth/utils/UrlBuilder.java +++ b/src/main/java/me/zhyd/oauth/utils/UrlBuilder.java @@ -35,6 +35,18 @@ public class UrlBuilder { private static final String BAIDU_AUTHORIZE_PATTERN = "{0}?client_id={1}&response_type=code&redirect_uri={2}&display=popup"; private static final String BAIDU_REVOKE_PATTERN = "{0}?access_token={1}"; + private static final String CSDN_ACCESS_TOKEN_PATTERN = "{0}?client_id={1}&client_secret={2}&grant_type=authorization_code&code={3}&redirect_uri={4}"; + private static final String CSDN_USER_INFO_PATTERN = "{0}?access_token={1}"; + private static final String CSDN_AUTHORIZE_PATTERN = "{0}?client_id={1}&response_type=code&redirect_uri={2}"; + + private static final String CODING_ACCESS_TOKEN_PATTERN = "{0}?client_id={1}&client_secret={2}&grant_type=authorization_code&code={3}"; + private static final String CODING_USER_INFO_PATTERN = "{0}?access_token={1}"; + private static final String CODING_AUTHORIZE_PATTERN = "{0}?client_id={1}&response_type=code&redirect_uri={2}"; + + private static final String OSCHINA_ACCESS_TOKEN_PATTERN = "{0}?client_id={1}&client_secret={2}&grant_type=authorization_code&code={3}&redirect_uri={4}&dataType=json"; + private static final String OSCHINA_USER_INFO_PATTERN = "{0}?access_token={1}&dataType=json"; + private static final String OSCHINA_AUTHORIZE_PATTERN = "{0}?client_id={1}&response_type=code&redirect_uri={2}"; + /** * 获取githubtoken的接口地址 * @@ -203,4 +215,105 @@ public class UrlBuilder { public static String getBaiduRevokeUrl(String accessToken) { return MessageFormat.format(BAIDU_REVOKE_PATTERN, ApiUrlConst.BAIDU_REVOKE_URL, accessToken); } + + /** + * 获取csdn token的接口地址 + * + * @param clientId csdn应用的App Key + * @param clientSecret csdn应用的App Secret + * @param code csdn授权前的code,用来换token + * @param redirectUri 待跳转的页面 + * @return full url + */ + public static String getCsdnAccessTokenUrl(String clientId, String clientSecret, String code, String redirectUri) { + return MessageFormat.format(CSDN_ACCESS_TOKEN_PATTERN, ApiUrlConst.CSDN_ACCESS_TOKEN_URL, clientId, clientSecret, code, redirectUri); + } + + /** + * 获取csdn用户详情的接口地址 + * + * @param token csdn 应用的token + * @return full url + */ + public static String getCsdnUserInfoUrl(String token) { + return MessageFormat.format(CSDN_USER_INFO_PATTERN, ApiUrlConst.CSDN_USER_INFO_URL, token); + } + + /** + * 获取csdn授权地址 + * + * @param clientId csdn 应用的Client ID + * @param redirectUrl csdn 应用授权成功后的回调地址 + * @return full url + */ + public static String getCsdnAuthorizeUrl(String clientId, String redirectUrl) { + return MessageFormat.format(CSDN_AUTHORIZE_PATTERN, ApiUrlConst.CSDN_AUTHORIZE_URL, clientId, redirectUrl); + } + + /** + * 获取coding token的接口地址 + * + * @param clientId coding应用的App Key + * @param clientSecret coding应用的App Secret + * @param code coding授权前的code,用来换token + * @return full url + */ + public static String getCodingAccessTokenUrl(String clientId, String clientSecret, String code) { + return MessageFormat.format(CODING_ACCESS_TOKEN_PATTERN, ApiUrlConst.CODING_ACCESS_TOKEN_URL, clientId, clientSecret, code); + } + + /** + * 获取coding用户详情的接口地址 + * + * @param token coding 应用的token + * @return full url + */ + public static String getCodingUserInfoUrl(String token) { + return MessageFormat.format(CODING_USER_INFO_PATTERN, ApiUrlConst.CODING_USER_INFO_URL, token); + } + + /** + * 获取coding授权地址 + * + * @param clientId coding 应用的Client ID + * @param redirectUrl coding 应用授权成功后的回调地址 + * @return full url + */ + public static String getCodingAuthorizeUrl(String clientId, String redirectUrl) { + return MessageFormat.format(CODING_AUTHORIZE_PATTERN, ApiUrlConst.CODING_AUTHORIZE_URL, clientId, redirectUrl); + } + + /** + * 获取oschina token的接口地址 + * + * @param clientId oschina应用的App Key + * @param clientSecret oschina应用的App Secret + * @param code oschina授权前的code,用来换token + * @param redirectUri 待跳转的页面 + * @return full url + */ + public static String getOschinaAccessTokenUrl(String clientId, String clientSecret, String code, String redirectUri) { + return MessageFormat.format(OSCHINA_ACCESS_TOKEN_PATTERN, ApiUrlConst.OSCHINA_ACCESS_TOKEN_URL, clientId, clientSecret, code, redirectUri); + } + + /** + * 获取oschina用户详情的接口地址 + * + * @param token oschina 应用的token + * @return full url + */ + public static String getOschinaUserInfoUrl(String token) { + return MessageFormat.format(OSCHINA_USER_INFO_PATTERN, ApiUrlConst.OSCHINA_USER_INFO_URL, token); + } + + /** + * 获取oschina授权地址 + * + * @param clientId oschina 应用的Client ID + * @param redirectUrl oschina 应用授权成功后的回调地址 + * @return full url + */ + public static String getOschinaAuthorizeUrl(String clientId, String redirectUrl) { + return MessageFormat.format(OSCHINA_AUTHORIZE_PATTERN, ApiUrlConst.OSCHINA_AUTHORIZE_URL, clientId, redirectUrl); + } } -- GitLab