From 87c2a1b2cd691cf19090a17fc5dffefc27c261b3 Mon Sep 17 00:00:00 2001 From: "Yangkai.Shen" <237497819@qq.com> Date: Fri, 17 May 2019 15:26:31 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20=E5=A2=9E=E5=8A=A0=E5=BE=AE?= =?UTF-8?q?=E4=BF=A1=E7=99=BB=E5=BD=95=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 6 + .../java/me/zhyd/oauth/consts/ApiUrl.java | 29 +++++ .../zhyd/oauth/request/AuthWeChatRequest.java | 106 ++++++++++++++++++ .../zhyd/oauth/request/BaseAuthRequest.java | 1 + .../java/me/zhyd/oauth/utils/UrlBuilder.java | 50 +++++++++ .../java/me/zhyd/oauth/AuthRequestTest.java | 14 +++ 6 files changed, 206 insertions(+) create mode 100644 src/main/java/me/zhyd/oauth/request/AuthWeChatRequest.java diff --git a/pom.xml b/pom.xml index 94f3fd5..f0e6846 100644 --- a/pom.xml +++ b/pom.xml @@ -31,6 +31,11 @@ yadong.zhang0415@gmail.com https://www.zhyd.me + + Yangkai.Shen + shenyangkai1994@gmail.com + https://xkcoding.com + @@ -46,6 +51,7 @@ 4.11 1.2.44 1.28.0 + 27.1-jre 3.7.4.ALL diff --git a/src/main/java/me/zhyd/oauth/consts/ApiUrl.java b/src/main/java/me/zhyd/oauth/consts/ApiUrl.java index f968e55..34fb1d8 100644 --- a/src/main/java/me/zhyd/oauth/consts/ApiUrl.java +++ b/src/main/java/me/zhyd/oauth/consts/ApiUrl.java @@ -329,6 +329,35 @@ public enum ApiUrl { public String refresh() { throw new AuthException(ResponseStatus.UNSUPPORTED); } + }, + /** + * 微信 + */ + WECHAT { + @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 revoke() { + throw new AuthException(ResponseStatus.UNSUPPORTED); + } + + @Override + public String refresh() { + return "https://api.weixin.qq.com/sns/oauth2/refresh_token"; + } }; public abstract String authorize(); diff --git a/src/main/java/me/zhyd/oauth/request/AuthWeChatRequest.java b/src/main/java/me/zhyd/oauth/request/AuthWeChatRequest.java new file mode 100644 index 0000000..257afaa --- /dev/null +++ b/src/main/java/me/zhyd/oauth/request/AuthWeChatRequest.java @@ -0,0 +1,106 @@ +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.AuthResponse; +import me.zhyd.oauth.model.AuthSource; +import me.zhyd.oauth.model.AuthUser; +import me.zhyd.oauth.model.AuthUserGender; +import me.zhyd.oauth.utils.UrlBuilder; + +/** + *

+ * 微信登录 + *

+ * + * @package: me.zhyd.oauth.request + * @description: 微信登录 + * @author: yangkai.shen + * @date: Created in 2019-05-17 11:11 + * @copyright: Copyright (c) 2019 + * @version: V1.0 + * @modified: yangkai.shen + */ +public class AuthWeChatRequest extends BaseAuthRequest { + public AuthWeChatRequest(AuthConfig config) { + super(config, AuthSource.WECHAT); + } + + /** + * 微信的特殊性,此时返回的信息同时包含 openid 和 access_token + * + * @param code 授权码 + * @return 所有信息 + */ + @Override + protected String getAccessToken(String code) { + String accessTokenUrl = UrlBuilder.getWeChatAccessTokenUrl(config.getClientId(), config.getClientSecret(), code); + HttpResponse response = HttpRequest.get(accessTokenUrl).execute(); + JSONObject accessTokenObject = JSONObject.parseObject(response.body()); + if (!accessTokenObject.containsKey("access_token") || !accessTokenObject.containsKey("openid") || !accessTokenObject + .containsKey("refresh_token")) { + throw new AuthException("Unable to get access_token or openid or refresh_token from wechat using code [" + code + "]"); + } + return response.body(); + } + + @Override + protected AuthUser getUserInfo(String accessToken) { + String token = this.getToken(accessToken); + String openId = this.getOpenId(accessToken); + + HttpResponse response = HttpRequest.get(UrlBuilder.getWeChatUserInfoUrl(token, openId)).execute(); + JSONObject object = JSONObject.parseObject(response.body()); + if (object.containsKey("errcode")) { + throw new AuthException(object.getString("errmsg")); + } + + return AuthUser.builder() + .username(object.getString("nickname")) + .nickname(object.getString("nickname")) + .avatar(object.getString("headimgurl")) + .location(object.getString("country") + "-" + object.getString("province") + "-" + object.getString("city")) + .gender(AuthUserGender.getRealGender(object.getString("sex"))) + .accessToken(accessToken) + .source(AuthSource.WECHAT) + .build(); + } + + /** + * 刷新access token (续期) + * + * @param accessToken 登录成功后返回的accessToken + * @return AuthResponse + */ + @Override + public AuthResponse refresh(String accessToken) { + String refreshToken = getRefreshToken(accessToken); + HttpResponse response = HttpRequest.get(UrlBuilder.getWeChatRefreshUrl(config.getClientId(), refreshToken)) + .execute(); + + JSONObject object = JSONObject.parseObject(response.body()); + if (object.containsKey("errcode")) { + throw new AuthException(object.getString("errmsg")); + } + + return AuthResponse.builder().data(object).build(); + } + + private String getRefreshToken(String accessToken) { + JSONObject accessTokenObject = JSONObject.parseObject(accessToken); + return accessTokenObject.getString("refresh_token"); + } + + private String getOpenId(String accessToken) { + JSONObject accessTokenObject = JSONObject.parseObject(accessToken); + return accessTokenObject.getString("openid"); + } + + private String getToken(String accessToken) { + JSONObject accessTokenObject = JSONObject.parseObject(accessToken); + return accessTokenObject.getString("access_token"); + } +} diff --git a/src/main/java/me/zhyd/oauth/request/BaseAuthRequest.java b/src/main/java/me/zhyd/oauth/request/BaseAuthRequest.java index a661e49..597328a 100644 --- a/src/main/java/me/zhyd/oauth/request/BaseAuthRequest.java +++ b/src/main/java/me/zhyd/oauth/request/BaseAuthRequest.java @@ -79,6 +79,7 @@ public abstract class BaseAuthRequest implements AuthRequest { authorizeUrl = UrlBuilder.getQqAuthorizeUrl(config.getClientId(), config.getRedirectUri()); break; case WECHAT: + authorizeUrl = UrlBuilder.getWeChatAuthorizeUrl(config.getClientId(), config.getRedirectUri()); break; case GOOGLE: break; diff --git a/src/main/java/me/zhyd/oauth/utils/UrlBuilder.java b/src/main/java/me/zhyd/oauth/utils/UrlBuilder.java index 44d091f..37392b2 100644 --- a/src/main/java/me/zhyd/oauth/utils/UrlBuilder.java +++ b/src/main/java/me/zhyd/oauth/utils/UrlBuilder.java @@ -56,6 +56,11 @@ public class UrlBuilder { private static final String QQ_AUTHORIZE_PATTERN = "{0}?client_id={1}&response_type=code&redirect_uri={2}&state={3}"; private static final String QQ_OPENID_PATTERN = "{0}?access_token={1}"; + private static final String WECHAT_AUTHORIZE_PATTERN = "{0}?appid={1}&redirect_uri={2}&response_type=code&scope=snsapi_userinfo#wechat_redirect"; + private static final String WECHAT_ACCESS_TOKEN_PATTERN = "{0}?appid={1}&secret={2}&code={3}&grant_type=authorization_code"; + private static final String WECHAT_REFRESH_TOKEN_PATTERN = "{0}?appid={1}&grant_type=refresh_token&refresh_token={2}"; + private static final String WECHAT_USER_INFO_PATTERN = "{0}?access_token={1}&openid={2}&lang=zh_CN"; + /** * 获取githubtoken的接口地址 * @@ -415,4 +420,49 @@ public class UrlBuilder { public static String getAlipayAuthorizeUrl(String clientId, String redirectUrl) { return MessageFormat.format(ALIPAY_AUTHORIZE_PATTERN, ApiUrl.ALIPAY.authorize(), clientId, redirectUrl); } + + /** + * 获取微信 授权地址 + * + * @param clientId 微信应用的appid + * @param redirectUrl 微信应用授权成功后的回调地址 + * @return full url + */ + public static String getWeChatAuthorizeUrl(String clientId, String redirectUrl) { + return MessageFormat.format(WECHAT_AUTHORIZE_PATTERN, ApiUrl.WECHAT.authorize(), clientId, redirectUrl); + } + + /** + * 获取微信 token的接口地址 + * + * @param clientId 微信应用的appid + * @param clientSecret 微信应用的secret + * @param code 微信授权前的code,用来换token + * @return full url + */ + public static String getWeChatAccessTokenUrl(String clientId, String clientSecret, String code) { + return MessageFormat.format(WECHAT_ACCESS_TOKEN_PATTERN, ApiUrl.WECHAT.accessToken(), clientId, clientSecret, code); + } + + /** + * 获取微信 用户详情的接口地址 + * + * @param token 微信应用返回的 access token + * @param openId 微信应用返回的openId + * @return full url + */ + public static String getWeChatUserInfoUrl(String token, String openId) { + return MessageFormat.format(WECHAT_USER_INFO_PATTERN, ApiUrl.WECHAT.userInfo(), token, openId); + } + + /** + * 获取微信 刷新令牌 地址 + * + * @param clientId 微信应用的appid + * @param refreshToken 微信应用返回的刷新token + * @return full url + */ + public static String getWeChatRefreshUrl(String clientId, String refreshToken) { + return MessageFormat.format(WECHAT_REFRESH_TOKEN_PATTERN, ApiUrl.WECHAT.refresh(), clientId, refreshToken); + } } diff --git a/src/test/java/me/zhyd/oauth/AuthRequestTest.java b/src/test/java/me/zhyd/oauth/AuthRequestTest.java index b027e97..8b67f23 100644 --- a/src/test/java/me/zhyd/oauth/AuthRequestTest.java +++ b/src/test/java/me/zhyd/oauth/AuthRequestTest.java @@ -1,6 +1,7 @@ package me.zhyd.oauth; import me.zhyd.oauth.config.AuthConfig; +import me.zhyd.oauth.model.AuthResponse; import me.zhyd.oauth.request.*; import org.junit.Test; @@ -114,4 +115,17 @@ public class AuthRequestTest { // 授权登录后会返回一个code,用这个code进行登录 authRequest.login("code"); } + + @Test + public void wechatTest() { + AuthRequest authRequest = new AuthWeChatRequest(AuthConfig.builder() + .clientId("clientId") + .clientSecret("clientSecret") + .redirectUri("redirectUri") + .build()); + // 返回授权页面,可自行调整 + String url = authRequest.authorize(); + // 授权登录后会返回一个code,用这个code进行登录 + AuthResponse login = authRequest.login("code"); + } } -- GitLab