mirror of
https://gitee.com/yadong.zhang/JustAuth.git
synced 2025-12-06 16:58:24 +08:00
支持企业微信网页授权登录
This commit is contained in:
parent
442332be57
commit
28e19960f2
@ -561,7 +561,7 @@ public enum AuthDefaultSource implements AuthSource {
|
|||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 企业微信
|
* 企业微信扫描登录
|
||||||
*
|
*
|
||||||
* @since 1.10.0
|
* @since 1.10.0
|
||||||
*/
|
*/
|
||||||
@ -582,6 +582,26 @@ public enum AuthDefaultSource implements AuthSource {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 企业微信网页登录
|
||||||
|
*/
|
||||||
|
WECHAT_ENTERPRISE_WEB {
|
||||||
|
@Override
|
||||||
|
public String authorize() {
|
||||||
|
return "https://open.weixin.qq.com/connect/oauth2/authorize";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String accessToken() {
|
||||||
|
return "https://qyapi.weixin.qq.com/cgi-bin/gettoken";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String userInfo() {
|
||||||
|
return "https://qyapi.weixin.qq.com/cgi-bin/user/getuserinfo";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 酷家乐
|
* 酷家乐
|
||||||
*
|
*
|
||||||
|
|||||||
@ -0,0 +1,24 @@
|
|||||||
|
package me.zhyd.oauth.enums.scope;
|
||||||
|
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 企业自建应用授权范围
|
||||||
|
*
|
||||||
|
* @author liguanhua(347826496@qq.com)
|
||||||
|
* @since 1.15.9
|
||||||
|
*/
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
public enum AuthWeChatEnterpriseWebScope implements AuthScope {
|
||||||
|
/**
|
||||||
|
* {@code scope} 含义,以{@code description} 为准
|
||||||
|
*/
|
||||||
|
SNSAPI_BASE("snsapi_base", "应用授权作用域。企业自建应用固定填写:snsapi_base", true);
|
||||||
|
|
||||||
|
private String scope;
|
||||||
|
private String description;
|
||||||
|
private boolean isDefault;
|
||||||
|
|
||||||
|
}
|
||||||
@ -0,0 +1,136 @@
|
|||||||
|
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.config.AuthSource;
|
||||||
|
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.AuthToken;
|
||||||
|
import me.zhyd.oauth.model.AuthUser;
|
||||||
|
import me.zhyd.oauth.utils.HttpUtils;
|
||||||
|
import me.zhyd.oauth.utils.UrlBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 企业微信登录父类
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author liguanhua(347826496@qq.com)
|
||||||
|
* @since 1.15.9
|
||||||
|
*/
|
||||||
|
public abstract class AbstractAuthWeChatEnterpriseRequest extends AuthDefaultRequest {
|
||||||
|
|
||||||
|
public AbstractAuthWeChatEnterpriseRequest(AuthConfig config, AuthSource source) {
|
||||||
|
super(config,source);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public AbstractAuthWeChatEnterpriseRequest(AuthConfig config, AuthSource source, AuthStateCache authStateCache) {
|
||||||
|
super(config, source, authStateCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
||||||
|
String response = doGetAuthorizationCode(accessTokenUrl(authCallback.getCode()));
|
||||||
|
|
||||||
|
JSONObject object = this.checkResponse(response);
|
||||||
|
|
||||||
|
return AuthToken.builder()
|
||||||
|
.accessToken(object.getString("access_token"))
|
||||||
|
.expireIn(object.getIntValue("expires_in"))
|
||||||
|
.code(authCallback.getCode())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected AuthUser getUserInfo(AuthToken authToken) {
|
||||||
|
String response = doGetUserInfo(authToken);
|
||||||
|
JSONObject object = this.checkResponse(response);
|
||||||
|
|
||||||
|
// 返回 OpenId 或其他,均代表非当前企业用户,不支持
|
||||||
|
if (!object.containsKey("UserId")) {
|
||||||
|
throw new AuthException(AuthResponseStatus.UNIDENTIFIED_PLATFORM, source);
|
||||||
|
}
|
||||||
|
String userId = object.getString("UserId");
|
||||||
|
String userDetailResponse = getUserDetail(authToken.getAccessToken(), userId);
|
||||||
|
JSONObject userDetail = this.checkResponse(userDetailResponse);
|
||||||
|
|
||||||
|
return AuthUser.builder()
|
||||||
|
.rawUserInfo(userDetail)
|
||||||
|
.username(userDetail.getString("name"))
|
||||||
|
.nickname(userDetail.getString("alias"))
|
||||||
|
.avatar(userDetail.getString("avatar"))
|
||||||
|
.location(userDetail.getString("address"))
|
||||||
|
.email(userDetail.getString("email"))
|
||||||
|
.uuid(userId)
|
||||||
|
.gender(AuthUserGender.getWechatRealGender(userDetail.getString("gender")))
|
||||||
|
.token(authToken)
|
||||||
|
.source(source.toString())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 校验请求结果
|
||||||
|
*
|
||||||
|
* @param response 请求结果
|
||||||
|
* @return 如果请求结果正常,则返回JSONObject
|
||||||
|
*/
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回获取accessToken的url
|
||||||
|
*
|
||||||
|
* @param code 授权码
|
||||||
|
* @return 返回获取accessToken的url
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String accessTokenUrl(String code) {
|
||||||
|
return UrlBuilder.fromBaseUrl(source.accessToken())
|
||||||
|
.queryParam("corpid", config.getClientId())
|
||||||
|
.queryParam("corpsecret", config.getClientSecret())
|
||||||
|
.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("code", authToken.getCode())
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 用户详情
|
||||||
|
*
|
||||||
|
* @param accessToken accessToken
|
||||||
|
* @param userId 企业内用户id
|
||||||
|
* @return 用户详情
|
||||||
|
*/
|
||||||
|
private String getUserDetail(String accessToken, String userId) {
|
||||||
|
String userDetailUrl = UrlBuilder.fromBaseUrl("https://qyapi.weixin.qq.com/cgi-bin/user/get")
|
||||||
|
.queryParam("access_token", accessToken)
|
||||||
|
.queryParam("userid", userId)
|
||||||
|
.build();
|
||||||
|
return new HttpUtils(config.getHttpConfig()).get(userDetailUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,27 +1,19 @@
|
|||||||
package me.zhyd.oauth.request;
|
package me.zhyd.oauth.request;
|
||||||
|
|
||||||
import com.alibaba.fastjson.JSONObject;
|
|
||||||
import me.zhyd.oauth.utils.HttpUtils;
|
|
||||||
import me.zhyd.oauth.cache.AuthStateCache;
|
import me.zhyd.oauth.cache.AuthStateCache;
|
||||||
import me.zhyd.oauth.config.AuthConfig;
|
import me.zhyd.oauth.config.AuthConfig;
|
||||||
import me.zhyd.oauth.config.AuthDefaultSource;
|
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.AuthToken;
|
|
||||||
import me.zhyd.oauth.model.AuthUser;
|
|
||||||
import me.zhyd.oauth.utils.UrlBuilder;
|
import me.zhyd.oauth.utils.UrlBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* 企业微信登录
|
* 企业微信二维码登录
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @author yangkai.shen (https://xkcoding.com)
|
* @author yangkai.shen (https://xkcoding.com)
|
||||||
* @since 1.10.0
|
* @since 1.10.0
|
||||||
*/
|
*/
|
||||||
public class AuthWeChatEnterpriseRequest extends AuthDefaultRequest {
|
public class AuthWeChatEnterpriseRequest extends AbstractAuthWeChatEnterpriseRequest {
|
||||||
public AuthWeChatEnterpriseRequest(AuthConfig config) {
|
public AuthWeChatEnterpriseRequest(AuthConfig config) {
|
||||||
super(config, AuthDefaultSource.WECHAT_ENTERPRISE);
|
super(config, AuthDefaultSource.WECHAT_ENTERPRISE);
|
||||||
}
|
}
|
||||||
@ -30,75 +22,6 @@ public class AuthWeChatEnterpriseRequest extends AuthDefaultRequest {
|
|||||||
super(config, AuthDefaultSource.WECHAT_ENTERPRISE, authStateCache);
|
super(config, AuthDefaultSource.WECHAT_ENTERPRISE, authStateCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 微信的特殊性,此时返回的信息同时包含 openid 和 access_token
|
|
||||||
*
|
|
||||||
* @param authCallback 回调返回的参数
|
|
||||||
* @return 所有信息
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected AuthToken getAccessToken(AuthCallback authCallback) {
|
|
||||||
String response = doGetAuthorizationCode(accessTokenUrl(authCallback.getCode()));
|
|
||||||
|
|
||||||
JSONObject object = this.checkResponse(response);
|
|
||||||
|
|
||||||
return AuthToken.builder()
|
|
||||||
.accessToken(object.getString("access_token"))
|
|
||||||
.expireIn(object.getIntValue("expires_in"))
|
|
||||||
.code(authCallback.getCode())
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected AuthUser getUserInfo(AuthToken authToken) {
|
|
||||||
String response = doGetUserInfo(authToken);
|
|
||||||
JSONObject object = this.checkResponse(response);
|
|
||||||
|
|
||||||
// 返回 OpenId 或其他,均代表非当前企业用户,不支持
|
|
||||||
if (!object.containsKey("UserId")) {
|
|
||||||
throw new AuthException(AuthResponseStatus.UNIDENTIFIED_PLATFORM, source);
|
|
||||||
}
|
|
||||||
String userId = object.getString("UserId");
|
|
||||||
String userDetailResponse = getUserDetail(authToken.getAccessToken(), userId);
|
|
||||||
JSONObject userDetail = this.checkResponse(userDetailResponse);
|
|
||||||
|
|
||||||
return AuthUser.builder()
|
|
||||||
.rawUserInfo(userDetail)
|
|
||||||
.username(userDetail.getString("name"))
|
|
||||||
.nickname(userDetail.getString("alias"))
|
|
||||||
.avatar(userDetail.getString("avatar"))
|
|
||||||
.location(userDetail.getString("address"))
|
|
||||||
.email(userDetail.getString("email"))
|
|
||||||
.uuid(userId)
|
|
||||||
.gender(AuthUserGender.getWechatRealGender(userDetail.getString("gender")))
|
|
||||||
.token(authToken)
|
|
||||||
.source(source.toString())
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 校验请求结果
|
|
||||||
*
|
|
||||||
* @param response 请求结果
|
|
||||||
* @return 如果请求结果正常,则返回JSONObject
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 返回带{@code state}参数的授权url,授权回调时会带上这个{@code state}
|
|
||||||
*
|
|
||||||
* @param state state 验证授权流程的参数,可以防止csrf
|
|
||||||
* @return 返回授权地址
|
|
||||||
* @since 1.9.3
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public String authorize(String state) {
|
public String authorize(String state) {
|
||||||
return UrlBuilder.fromBaseUrl(source.authorize())
|
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||||
@ -108,48 +31,4 @@ public class AuthWeChatEnterpriseRequest extends AuthDefaultRequest {
|
|||||||
.queryParam("state", getRealState(state))
|
.queryParam("state", getRealState(state))
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 返回获取accessToken的url
|
|
||||||
*
|
|
||||||
* @param code 授权码
|
|
||||||
* @return 返回获取accessToken的url
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
protected String accessTokenUrl(String code) {
|
|
||||||
return UrlBuilder.fromBaseUrl(source.accessToken())
|
|
||||||
.queryParam("corpid", config.getClientId())
|
|
||||||
.queryParam("corpsecret", config.getClientSecret())
|
|
||||||
.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("code", authToken.getCode())
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 用户详情
|
|
||||||
*
|
|
||||||
* @param accessToken accessToken
|
|
||||||
* @param userId 企业内用户id
|
|
||||||
* @return 用户详情
|
|
||||||
*/
|
|
||||||
private String getUserDetail(String accessToken, String userId) {
|
|
||||||
String userDetailUrl = UrlBuilder.fromBaseUrl("https://qyapi.weixin.qq.com/cgi-bin/user/get")
|
|
||||||
.queryParam("access_token", accessToken)
|
|
||||||
.queryParam("userid", userId)
|
|
||||||
.build();
|
|
||||||
return new HttpUtils(config.getHttpConfig()).get(userDetailUrl);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -0,0 +1,37 @@
|
|||||||
|
package me.zhyd.oauth.request;
|
||||||
|
|
||||||
|
import me.zhyd.oauth.cache.AuthStateCache;
|
||||||
|
import me.zhyd.oauth.config.AuthConfig;
|
||||||
|
import me.zhyd.oauth.config.AuthDefaultSource;
|
||||||
|
import me.zhyd.oauth.enums.scope.AuthWeChatEnterpriseWebScope;
|
||||||
|
import me.zhyd.oauth.utils.AuthScopeUtils;
|
||||||
|
import me.zhyd.oauth.utils.UrlBuilder;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* 企业微信网页登录
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @author liguanhua(347826496@qq.com)
|
||||||
|
* @since 1.15.9
|
||||||
|
*/
|
||||||
|
public class AuthWeChatEnterpriseWebRequest extends AbstractAuthWeChatEnterpriseRequest {
|
||||||
|
public AuthWeChatEnterpriseWebRequest(AuthConfig config) {
|
||||||
|
super(config, AuthDefaultSource.WECHAT_ENTERPRISE_WEB);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AuthWeChatEnterpriseWebRequest(AuthConfig config, AuthStateCache authStateCache) {
|
||||||
|
super(config, AuthDefaultSource.WECHAT_ENTERPRISE_WEB, authStateCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String authorize(String state) {
|
||||||
|
return UrlBuilder.fromBaseUrl(source.authorize())
|
||||||
|
.queryParam("appid", config.getClientId())
|
||||||
|
.queryParam("redirect_uri", config.getRedirectUri())
|
||||||
|
.queryParam("response_type", "code")
|
||||||
|
.queryParam("scope", this.getScopes(",", false, AuthScopeUtils.getDefaultScopes(AuthWeChatEnterpriseWebScope.values())))
|
||||||
|
.queryParam("state", getRealState(state).concat("#wechat_redirect"))
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user