diff --git a/src/main/java/me/zhyd/oauth/config/AuthConfig.java b/src/main/java/me/zhyd/oauth/config/AuthConfig.java index 38f4cccebc03df53439654602b4732dfe392c83a..752464b6e32bddf285315b49cac46f2071f88f3f 100644 --- a/src/main/java/me/zhyd/oauth/config/AuthConfig.java +++ b/src/main/java/me/zhyd/oauth/config/AuthConfig.java @@ -65,6 +65,13 @@ public class AuthConfig { */ private String agentId; + /** + * 企业微信第三方授权用户类型,member|admin + * + * @since 1.10.0 + */ + private String usertype; + /** * 域名前缀。 *

diff --git a/src/main/java/me/zhyd/oauth/config/AuthDefaultSource.java b/src/main/java/me/zhyd/oauth/config/AuthDefaultSource.java index ea99d3d7467e510a65d99dbef479529c1d708450..133986665b92d0073cfc5c584a9d3f5099e8af05 100644 --- a/src/main/java/me/zhyd/oauth/config/AuthDefaultSource.java +++ b/src/main/java/me/zhyd/oauth/config/AuthDefaultSource.java @@ -600,7 +600,40 @@ public enum AuthDefaultSource implements AuthSource { return "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo"; } }, + /** + * 企业微信二维码第三方登录 + */ + WECHAT_ENTERPRISE_QRCODE_THIRD { + /** + * 授权的api + * + * @return url + */ + @Override + public String authorize() { + return "https://open.work.weixin.qq.com/wwopen/sso/3rd_qrConnect"; + } + + /** + * 获取accessToken的api + * + * @return url + */ + @Override + public String accessToken() { + return "https://qyapi.weixin.qq.com/cgi-bin/service/get_provider_token"; + } + /** + * 获取用户信息的api + * + * @return url + */ + @Override + public String userInfo() { + return "https://qyapi.weixin.qq.com/cgi-bin/service/get_login_info"; + } + }, /** * 企业微信网页登录 */ diff --git a/src/main/java/me/zhyd/oauth/request/AuthDefaultRequest.java b/src/main/java/me/zhyd/oauth/request/AuthDefaultRequest.java index b765297c4e1c9f281c6e823cd8f7ae2bedbda614..8a949faee054902ede6c84d93a25e31a06fd5c5d 100644 --- a/src/main/java/me/zhyd/oauth/request/AuthDefaultRequest.java +++ b/src/main/java/me/zhyd/oauth/request/AuthDefaultRequest.java @@ -92,7 +92,7 @@ public abstract class AuthDefaultRequest implements AuthRequest { * @param e 具体的异常 * @return AuthResponse */ - private AuthResponse responseError(Exception e) { + AuthResponse responseError(Exception e) { int errorCode = AuthResponseStatus.FAILURE.getCode(); String errorMsg = e.getMessage(); if (e instanceof AuthException) { diff --git a/src/main/java/me/zhyd/oauth/request/AuthWeChatEnterpriseThirdQrcodeRequest.java b/src/main/java/me/zhyd/oauth/request/AuthWeChatEnterpriseThirdQrcodeRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..0f85f217153aa41187070dbafe083e47071d2a2b --- /dev/null +++ b/src/main/java/me/zhyd/oauth/request/AuthWeChatEnterpriseThirdQrcodeRequest.java @@ -0,0 +1,119 @@ +package me.zhyd.oauth.request; + +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.exception.AuthException; +import me.zhyd.oauth.log.Log; +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.*; + +/** + *

+ * 企业微信第三方二维码登录 + *

+ * + * @author zhengjx + * @since 1.10.0 + */ +public class AuthWeChatEnterpriseThirdQrcodeRequest extends AbstractAuthWeChatEnterpriseRequest { + public AuthWeChatEnterpriseThirdQrcodeRequest(AuthConfig config) { + super(config, AuthDefaultSource.WECHAT_ENTERPRISE_QRCODE_THIRD); + } + + public AuthWeChatEnterpriseThirdQrcodeRequest(AuthConfig config, AuthStateCache authStateCache) { + super(config, AuthDefaultSource.WECHAT_ENTERPRISE_QRCODE_THIRD, authStateCache); + } + + @Override + public String authorize(String state) { + return UrlBuilder.fromBaseUrl(source.authorize()) + .queryParam("appid", config.getClientId()) + .queryParam("redirect_uri", config.getRedirectUri()) + .queryParam("state", getRealState(state)) + .queryParam("usertype", config.getUsertype()) + .build(); + } + + @Override + public AuthResponse login(AuthCallback authCallback) { + try { + if (!config.isIgnoreCheckState()) { + AuthChecker.checkState(authCallback.getState(), source, authStateCache); + } + AuthToken authToken = this.getAccessToken(authCallback); + AuthUser user = this.getUserInfo(authToken); + return AuthResponse.builder().code(AuthResponseStatus.SUCCESS.getCode()).data(user).build(); + } catch (Exception e) { + Log.error("Failed to login with oauth authorization.", e); + return this.responseError(e); + } + } + + @Override + protected AuthToken getAccessToken(AuthCallback authCallback) { + try { + String response = doGetAuthorizationCode(accessTokenUrl()); + JSONObject object = this.checkResponse(response); + AuthToken authToken = AuthToken.builder() + .accessToken(object.getString("provider_access_token")) + .expireIn(object.getIntValue("expires_in")) + .build(); + return authToken; + } catch (Exception e) { + throw new AuthException("企业微信获取token失败", e); + } + } + + @Override + protected String doGetAuthorizationCode(String code) { + JSONObject data = new JSONObject(); + data.put("corpid", config.getClientId()); + data.put("provider_secret", config.getClientSecret()); + return new HttpUtils(config.getHttpConfig()).post(accessTokenUrl(code), data.toJSONString()); + } + + /** + * 获取token的URL + * + * @return + */ + protected String accessTokenUrl() { + return UrlBuilder.fromBaseUrl(source.accessToken()) + .build(); + } + + @Override + protected AuthUser getUserInfo(AuthToken authToken) { + JSONObject response = this.checkResponse(doGetUserInfo(authToken)); + return AuthUser.builder() + .rawUserInfo(response) + .build(); + } + + protected String doGetUserInfo(AuthToken authToken) { + JSONObject data = new JSONObject(); + data.put("auth_code", authToken.getCode()); + return new HttpUtils(config.getHttpConfig()) + .post(userInfoUrl(authToken), data.toJSONString()); + } + + protected String userInfoUrl(AuthToken authToken) { + return UrlBuilder.fromBaseUrl(source.userInfo()) + .queryParam("access_token", authToken.getAccessToken()). + build(); + } + + private JSONObject checkResponse(String response) { + JSONObject object = JSONObject.parseObject(response); + if (object.containsKey("errcode") && object.getIntValue("errcode") != 0) { + throw new AuthException(object.getString("errmsg"), source); + } + return object; + } +}