diff --git a/README.md b/README.md
index d71e1c26a445c9612d897f87d29cf250fa58c95b..e9c24c9dee84973c771f095028a99fd09c534e67 100644
--- a/README.md
+++ b/README.md
@@ -24,8 +24,10 @@
![](https://gitee.com/yadong.zhang/static/raw/master/JustAuth/github.png) |
![](https://gitee.com/yadong.zhang/static/raw/master/JustAuth/weibo.png) |
![](https://gitee.com/yadong.zhang/static/raw/master/JustAuth/dingding.png) |
- ![](https://gitee.com/yadong.zhang/static/raw/master/JustAuth/baidu.png) |
+ ![](https://gitee.com/yadong.zhang/static/raw/master/JustAuth/baidu.png) |
![](https://gitee.com/yadong.zhang/static/raw/master/JustAuth/csdn.png) |
+ ![](https://gitee.com/yadong.zhang/static/raw/master/JustAuth/coding.png) |
+ ![](https://gitee.com/yadong.zhang/static/raw/master/JustAuth/oschinas.png) |
![](https://gitee.com/yadong.zhang/static/raw/master/JustAuth/qq.png) |
![](https://gitee.com/yadong.zhang/static/raw/master/JustAuth/wechats.png) |
@@ -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 acce7b1ad61eefd51e4fa153e4e7f5ce0b9b2022..0928f24265c16d4a5ec950869084a6701c631cbd 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 82ff82573d1c9c271ab3ab322e5becbfd5435c4b..5baed22418ebde52359d3ec9a5dd36d663d02697 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 5dac4ab488b89fb2e942b96b042c3216154dfd20..b501ebbc8e0465d1ca1e1cd15561254a2428c27f 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 0000000000000000000000000000000000000000..3fa1e7a735d1112d9a04684262d23f7e756c102d
--- /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 0000000000000000000000000000000000000000..5bafe9379807230248b2b1be1e36aa67501927e0
--- /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 06c25e788e582d09d28afc5b29ec51c1ea7964f6..14962d56f922c4fad57ca6992c3aae7029f1fd95 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 0000000000000000000000000000000000000000..084e41f8511f3225d5351530fb9f977ff171cdcd
--- /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 f82948fb864dbeec70048cdba6796f7cdb41e738..6f3b6fce24f4bf8b9d95ac680a200062855961df 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 90388f99c6d1e55b9d0809cc79598a06954fb675..7ef35d7b35ed4d34f8f5e807223951fd762e6fa7 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 aa2c51e0fd6c6288f050759d287a0fc57cfcd8fb..e7f6bf738a33f24569bf9d8e67d191ac6c6c235c 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 dea7f4ff52c637ef8260b4659f9a90c55372e69b..83a7f1dcfa598ff2324b0e3ea2aed6aad47a359a 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);
+ }
}