From 4d2518e21a4800a4af64245842af382691749f15 Mon Sep 17 00:00:00 2001
From: "Yangkai.Shen" <237497819@qq.com>
Date: Mon, 16 Dec 2019 19:10:01 +0800
Subject: [PATCH] =?UTF-8?q?:sparkles:=20=E9=9B=86=E6=88=90=E5=BE=AE?=
=?UTF-8?q?=E4=BF=A1=E5=85=AC=E4=BC=97=E5=8F=B7=E7=99=BB=E5=BD=95=EF=BC=8C?=
=?UTF-8?q?=E4=BF=AE=E6=94=B9=E4=B9=8B=E5=89=8D=E7=9A=84=E5=BE=AE=E4=BF=A1?=
=?UTF-8?q?=E7=99=BB=E5=BD=95=E4=B8=BA=E5=BE=AE=E4=BF=A1=E5=BC=80=E6=94=BE?=
=?UTF-8?q?=E5=B9=B3=E5=8F=B0=E7=99=BB=E5=BD=95?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
docs/oauth/wechat.md | 4 +-
pom.xml | 2 +-
.../zhyd/oauth/config/AuthDefaultSource.java | 28 ++-
.../oauth/request/AuthWeChatMpRequest.java | 187 ++++++++++++++++++
...equest.java => AuthWeChatOpenRequest.java} | 12 +-
.../me/zhyd/oauth/utils/UrlBuilderTest.java | 6 +-
6 files changed, 225 insertions(+), 14 deletions(-)
create mode 100644 src/main/java/me/zhyd/oauth/request/AuthWeChatMpRequest.java
rename src/main/java/me/zhyd/oauth/request/{AuthWeChatRequest.java => AuthWeChatOpenRequest.java} (93%)
diff --git a/docs/oauth/wechat.md b/docs/oauth/wechat.md
index b579bf5..bd67ec7 100644
--- a/docs/oauth/wechat.md
+++ b/docs/oauth/wechat.md
@@ -79,7 +79,7 @@ String authorizeUrl = authRequest.authorize(AuthStateUtils.createState());
```java
import me.zhyd.oauth.config.AuthConfig;
-import me.zhyd.oauth.request.AuthWeChatRequest;
+import me.zhyd.oauth.request.AuthWeChatOpenRequest;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.utils.AuthStateUtils;
import org.springframework.web.bind.annotation.PathVariable;
@@ -107,7 +107,7 @@ public class RestAuthController {
}
private AuthRequest getAuthRequest() {
- return new AuthWeChatRequest(AuthConfig.builder()
+ return new AuthWeChatOpenRequest(AuthConfig.builder()
.clientId("Client ID")
.clientSecret("Client Secret")
.redirectUri("https://www.zhyd.me/oauth/callback/wechat")
diff --git a/pom.xml b/pom.xml
index a4f365c..9b0f2f4 100644
--- a/pom.xml
+++ b/pom.xml
@@ -6,7 +6,7 @@
me.zhyd.oauth
JustAuth
- 1.13.1
+ 1.13.2-SNAPSHOT
JustAuth
https://gitee.com/yadong.zhang/JustAuth
diff --git a/src/main/java/me/zhyd/oauth/config/AuthDefaultSource.java b/src/main/java/me/zhyd/oauth/config/AuthDefaultSource.java
index a029f66..09f67d8 100644
--- a/src/main/java/me/zhyd/oauth/config/AuthDefaultSource.java
+++ b/src/main/java/me/zhyd/oauth/config/AuthDefaultSource.java
@@ -240,9 +240,9 @@ public enum AuthDefaultSource implements AuthSource {
}
},
/**
- * 微信
+ * 微信开放平台
*/
- WECHAT {
+ WECHAT_OPEN {
@Override
public String authorize() {
return "https://open.weixin.qq.com/connect/qrconnect";
@@ -263,6 +263,30 @@ public enum AuthDefaultSource implements AuthSource {
return "https://api.weixin.qq.com/sns/oauth2/refresh_token";
}
},
+ /**
+ * 微信公众平台
+ */
+ WECHAT_MP {
+ @Override
+ public String authorize() {
+ return "https://open.weixin.qq.com/connect/oauth2/authorize";
+ }
+
+ @Override
+ public String accessToken() {
+ return "https://api.weixin.qq.com/sns/oauth2/access_token";
+ }
+
+ @Override
+ public String userInfo() {
+ return "https://api.weixin.qq.com/sns/userinfo";
+ }
+
+ @Override
+ public String refresh() {
+ return "https://api.weixin.qq.com/sns/oauth2/refresh_token";
+ }
+ },
/**
* 淘宝
*/
diff --git a/src/main/java/me/zhyd/oauth/request/AuthWeChatMpRequest.java b/src/main/java/me/zhyd/oauth/request/AuthWeChatMpRequest.java
new file mode 100644
index 0000000..ac67094
--- /dev/null
+++ b/src/main/java/me/zhyd/oauth/request/AuthWeChatMpRequest.java
@@ -0,0 +1,187 @@
+package me.zhyd.oauth.request;
+
+import cn.hutool.http.HttpRequest;
+import cn.hutool.http.HttpResponse;
+import com.alibaba.fastjson.JSONObject;
+import me.zhyd.oauth.cache.AuthStateCache;
+import me.zhyd.oauth.config.AuthConfig;
+import me.zhyd.oauth.config.AuthDefaultSource;
+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.AuthResponse;
+import me.zhyd.oauth.model.AuthToken;
+import me.zhyd.oauth.model.AuthUser;
+import me.zhyd.oauth.utils.GlobalAuthUtil;
+import me.zhyd.oauth.utils.UrlBuilder;
+
+/**
+ * 微信公众平台登录
+ *
+ * @author yangkai.shen (https://xkcoding.com)
+ * @since 1.1.0
+ */
+public class AuthWeChatMpRequest extends AuthDefaultRequest {
+ public AuthWeChatMpRequest(AuthConfig config) {
+ super(config, AuthDefaultSource.WECHAT_MP);
+ }
+
+ public AuthWeChatMpRequest(AuthConfig config, AuthStateCache authStateCache) {
+ super(config, AuthDefaultSource.WECHAT_MP, authStateCache);
+ }
+
+ /**
+ * 微信的特殊性,此时返回的信息同时包含 openid 和 access_token
+ *
+ * @param authCallback 回调返回的参数
+ * @return 所有信息
+ */
+ @Override
+ protected AuthToken getAccessToken(AuthCallback authCallback) {
+ return this.getToken(accessTokenUrl(authCallback.getCode()));
+ }
+
+ @Override
+ protected AuthUser getUserInfo(AuthToken authToken) {
+ String openId = authToken.getOpenId();
+
+ HttpResponse response = doGetUserInfo(authToken);
+ JSONObject object = JSONObject.parseObject(response.body());
+
+ this.checkResponse(object);
+
+ String location = String.format("%s-%s-%s", object.getString("country"), object.getString("province"), object.getString("city"));
+
+ if (object.containsKey("unionid")) {
+ authToken.setUnionId(object.getString("unionid"));
+ }
+
+ AuthUserGender sex;
+ switch (object.getString("sex")) {
+ case "1":
+ sex = AuthUserGender.MALE;
+ break;
+ case "2":
+ sex = AuthUserGender.FEMALE;
+ break;
+ default:
+ sex = AuthUserGender.UNKNOWN;
+ }
+
+ return AuthUser.builder()
+ .username(object.getString("nickname"))
+ .nickname(object.getString("nickname"))
+ .avatar(object.getString("headimgurl"))
+ .location(location)
+ .uuid(openId)
+ .gender(sex)
+ .token(authToken)
+ .source(source.toString())
+ .build();
+ }
+
+ @Override
+ public AuthResponse refresh(AuthToken oldToken) {
+ return AuthResponse.builder()
+ .code(AuthResponseStatus.SUCCESS.getCode())
+ .data(this.getToken(refreshTokenUrl(oldToken.getRefreshToken())))
+ .build();
+ }
+
+ /**
+ * 检查响应内容是否正确
+ *
+ * @param object 请求响应内容
+ */
+ private void checkResponse(JSONObject object) {
+ if (object.containsKey("errcode")) {
+ throw new AuthException(object.getIntValue("errcode"), object.getString("errmsg"));
+ }
+ }
+
+ /**
+ * 获取token,适用于获取access_token和刷新token
+ *
+ * @param accessTokenUrl 实际请求token的地址
+ * @return token对象
+ */
+ private AuthToken getToken(String accessTokenUrl) {
+ HttpResponse response = HttpRequest.get(accessTokenUrl).execute();
+ JSONObject accessTokenObject = JSONObject.parseObject(response.body());
+
+ this.checkResponse(accessTokenObject);
+
+ return AuthToken.builder()
+ .accessToken(accessTokenObject.getString("access_token"))
+ .refreshToken(accessTokenObject.getString("refresh_token"))
+ .expireIn(accessTokenObject.getIntValue("expires_in"))
+ .openId(accessTokenObject.getString("openid"))
+ .scope(accessTokenObject.getString("scope"))
+ .build();
+ }
+
+ /**
+ * 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
+ *
+ * @param state state 验证授权流程的参数,可以防止csrf
+ * @return 返回授权地址
+ * @since 1.9.3
+ */
+ @Override
+ public String authorize(String state) {
+ return UrlBuilder.fromBaseUrl(source.authorize())
+ .queryParam("appid", config.getClientId())
+ .queryParam("redirect_uri", GlobalAuthUtil.urlEncode(config.getRedirectUri()))
+ .queryParam("response_type", "code")
+ .queryParam("scope", "snsapi_userinfo")
+ .queryParam("state", getRealState(state).concat("#wechat_redirect"))
+ .build();
+ }
+
+ /**
+ * 返回获取accessToken的url
+ *
+ * @param code 授权码
+ * @return 返回获取accessToken的url
+ */
+ @Override
+ protected String accessTokenUrl(String code) {
+ return UrlBuilder.fromBaseUrl(source.accessToken())
+ .queryParam("appid", config.getClientId())
+ .queryParam("secret", config.getClientSecret())
+ .queryParam("code", code)
+ .queryParam("grant_type", "authorization_code")
+ .build();
+ }
+
+ /**
+ * 返回获取userInfo的url
+ *
+ * @param authToken 用户授权后的token
+ * @return 返回获取userInfo的url
+ */
+ @Override
+ protected String userInfoUrl(AuthToken authToken) {
+ return UrlBuilder.fromBaseUrl(source.userInfo())
+ .queryParam("access_token", authToken.getAccessToken())
+ .queryParam("openid", authToken.getOpenId())
+ .queryParam("lang", "zh_CN")
+ .build();
+ }
+
+ /**
+ * 返回获取userInfo的url
+ *
+ * @param refreshToken getAccessToken方法返回的refreshToken
+ * @return 返回获取userInfo的url
+ */
+ @Override
+ protected String refreshTokenUrl(String refreshToken) {
+ return UrlBuilder.fromBaseUrl(source.refresh())
+ .queryParam("appid", config.getClientId())
+ .queryParam("grant_type", "refresh_token")
+ .queryParam("refresh_token", refreshToken)
+ .build();
+ }
+}
diff --git a/src/main/java/me/zhyd/oauth/request/AuthWeChatRequest.java b/src/main/java/me/zhyd/oauth/request/AuthWeChatOpenRequest.java
similarity index 93%
rename from src/main/java/me/zhyd/oauth/request/AuthWeChatRequest.java
rename to src/main/java/me/zhyd/oauth/request/AuthWeChatOpenRequest.java
index 1e78d58..d46a1fc 100644
--- a/src/main/java/me/zhyd/oauth/request/AuthWeChatRequest.java
+++ b/src/main/java/me/zhyd/oauth/request/AuthWeChatOpenRequest.java
@@ -16,18 +16,18 @@ import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.utils.UrlBuilder;
/**
- * 微信登录
+ * 微信开放平台登录
*
* @author yangkai.shen (https://xkcoding.com)
* @since 1.1.0
*/
-public class AuthWeChatRequest extends AuthDefaultRequest {
- public AuthWeChatRequest(AuthConfig config) {
- super(config, AuthDefaultSource.WECHAT);
+public class AuthWeChatOpenRequest extends AuthDefaultRequest {
+ public AuthWeChatOpenRequest(AuthConfig config) {
+ super(config, AuthDefaultSource.WECHAT_OPEN);
}
- public AuthWeChatRequest(AuthConfig config, AuthStateCache authStateCache) {
- super(config, AuthDefaultSource.WECHAT, authStateCache);
+ public AuthWeChatOpenRequest(AuthConfig config, AuthStateCache authStateCache) {
+ super(config, AuthDefaultSource.WECHAT_OPEN, authStateCache);
}
/**
diff --git a/src/test/java/me/zhyd/oauth/utils/UrlBuilderTest.java b/src/test/java/me/zhyd/oauth/utils/UrlBuilderTest.java
index 86b6789..a2a8a69 100644
--- a/src/test/java/me/zhyd/oauth/utils/UrlBuilderTest.java
+++ b/src/test/java/me/zhyd/oauth/utils/UrlBuilderTest.java
@@ -2,7 +2,7 @@ package me.zhyd.oauth.utils;
import me.zhyd.oauth.config.AuthConfig;
import me.zhyd.oauth.config.AuthDefaultSource;
-import me.zhyd.oauth.request.AuthWeChatRequest;
+import me.zhyd.oauth.request.AuthWeChatOpenRequest;
import org.junit.Assert;
import org.junit.Test;
@@ -22,7 +22,7 @@ public class UrlBuilderTest {
.clientSecret("secret-110110110")
.redirectUri("https://xkcoding.com")
.build();
- String build = UrlBuilder.fromBaseUrl(AuthDefaultSource.WECHAT.authorize())
+ String build = UrlBuilder.fromBaseUrl(AuthDefaultSource.WECHAT_OPEN.authorize())
.queryParam("appid", config.getClientId())
.queryParam("redirect_uri", config.getRedirectUri())
.queryParam("response_type", "code")
@@ -30,7 +30,7 @@ public class UrlBuilderTest {
.queryParam("state", "")
.build(false);
System.out.println(build);
- AuthWeChatRequest request = new AuthWeChatRequest(config);
+ AuthWeChatOpenRequest request = new AuthWeChatOpenRequest(config);
String authorize = request.authorize("state");
System.out.println(authorize);
}