提交 9fd2b9b9 编写于 作者: 智布道's avatar 智布道 👁

🥚 正式启用飞书登录

上级 2ff55703
......@@ -3,6 +3,9 @@
### 2021/1/1
- 发布 v1.15.9
- 新增
- 修复并正式启用 飞书 平台的第三方登录
- AuthToken 类中新增 `refreshTokenExpireIn` 记录 refresh token 的有效期
- PR
- 合并 [Github #101](https://gitee.com/yadong.zhang/JustAuth/pulls/101):支持喜马拉雅登录
- 合并 [Github #105](https://gitee.com/yadong.zhang/JustAuth/pulls/105):支持企业微信网页授权登录
......
......@@ -141,7 +141,7 @@ public enum AuthDefaultSource implements AuthSource {
},
/**
* Coding,
*
* <p>
* 参考 https://help.coding.net/docs/project/open/oauth.html#%E7%94%A8%E6%88%B7%E6%8E%88%E6%9D%83 中的说明,
* 新版的 coding API 地址需要传入用户团队名,这儿使用动态参数,方便在 request 中使用
*/
......@@ -730,30 +730,31 @@ public enum AuthDefaultSource implements AuthSource {
},
/**
* 飞书
* 注意:该平台暂时存在问题,请不要使用。待修复完成后会重新发版
* 飞书平台,企业自建应用授权登录,原逻辑由 beacon 集成于 1.14.0 版,但最新的飞书 api 已修改,并且飞书平台一直为 {@code Deprecated} 状态
* <p>
* 所以,最终修改该平台的实际发布版本为 1.15.9
*
* @since 1.14.0
* @since 1.15.9
*/
FEISHU {
@Override
public String authorize() {
return "https://open.feishu.cn/connect/qrconnect/page/sso/";
return "https://open.feishu.cn/open-apis/authen/v1/index";
}
@Override
public String accessToken() {
return "https://open.feishu.cn/connect/qrconnect/oauth2/access_token/";
return "https://open.feishu.cn/open-apis/authen/v1/access_token";
}
@Override
public String userInfo() {
return "https://open.feishu.cn/connect/qrconnect/oauth2/user_info/";
return "https://open.feishu.cn/open-apis/authen/v1/user_info";
}
@Override
public String refresh() {
return "https://open.feishu.cn/connect/qrconnect/oauth2/access_token/";
return "https://open.feishu.cn/open-apis/authen/v1/refresh_access_token";
}
},
/**
......
......@@ -19,6 +19,7 @@ public class AuthToken implements Serializable {
private String accessToken;
private int expireIn;
private String refreshToken;
private int refreshTokenExpireIn;
private String uid;
private String openId;
private String accessCode;
......
......@@ -3,9 +3,11 @@ package me.zhyd.oauth.request;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xkcoding.http.support.HttpHeader;
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;
......@@ -13,40 +15,63 @@ import me.zhyd.oauth.model.AuthToken;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.utils.GlobalAuthUtils;
import me.zhyd.oauth.utils.HttpUtils;
import me.zhyd.oauth.utils.StringUtils;
import me.zhyd.oauth.utils.UrlBuilder;
/**
* 注意:该平台暂时存在问题,请不要使用。待修复完成后会重新发版by yadong.zhang
* 飞书平台,企业自建应用授权登录,原逻辑由 beacon 集成于 1.14.0 版,但最新的飞书 api 已修改,并且飞书平台一直为 {@code Deprecated} 状态
* <p>
* 所以,最终修改该平台的实际发布版本为 1.15.9
*
* @author beacon
* @since 1.14.0
* @author yadong.zhang (yadong.zhang0415(a)gmail.com) 重构业务逻辑 20210101
* @since 1.15.9
*/
@Deprecated
public class AuthFeishuRequest extends AuthDefaultRequest {
public AuthFeishuRequest(AuthConfig config) {
super(config, AuthDefaultSource.FEISHU);
throw new AuthException(AuthResponseStatus.FAILURE);
}
@Override
protected AuthToken getAccessToken(AuthCallback authCallback) {
public AuthFeishuRequest(AuthConfig config, AuthStateCache authStateCache) {
super(config, AuthDefaultSource.FEISHU, authStateCache);
}
/**
* 获取 app_access_token(企业自建应用)
* <p>
* Token 有效期为 2 小时,在此期间调用该接口 token 不会改变。当 token 有效期小于 30 分的时候,再次请求获取 token 的时候,
* 会生成一个新的 token,与此同时老的 token 依然有效。
*
* @return appAccessToken
*/
private String getAppAccessToken() {
String cacheKey = this.source.getName().concat(":app_access_token:").concat(config.getClientId());
String cacheAppAccessToken = this.authStateCache.get(cacheKey);
if (StringUtils.isNotEmpty(cacheAppAccessToken)) {
return cacheAppAccessToken;
}
String url = "https://open.feishu.cn/open-apis/auth/v3/app_access_token/internal/";
JSONObject requestObject = new JSONObject();
requestObject.put("app_id", config.getClientId());
requestObject.put("app_secret", config.getClientSecret());
requestObject.put("grant_type", "authorization_code");
requestObject.put("code", authCallback.getCode());
String response = new HttpUtils(config.getHttpConfig()).post(source.accessToken(), requestObject.toJSONString(), new HttpHeader()
String response = new HttpUtils(config.getHttpConfig()).post(url, requestObject.toJSONString(), new HttpHeader()
.add("Content-Type", "application/json"));
JSONObject jsonObject = JSON.parseObject(response);
this.checkResponse(jsonObject);
return AuthToken.builder()
.accessToken(jsonObject.getString("access_token"))
.refreshToken(jsonObject.getString("refresh_token"))
.expireIn(jsonObject.getIntValue("expires_in"))
.tokenType(jsonObject.getString("token_type"))
.openId(jsonObject.getString("open_id"))
.build();
String appAccessToken = jsonObject.getString("app_access_token");
// 缓存 app access token
this.authStateCache.cache(cacheKey, appAccessToken, jsonObject.getLongValue("expire") * 1000);
return appAccessToken;
}
@Override
protected AuthToken getAccessToken(AuthCallback authCallback) {
JSONObject requestObject = new JSONObject();
requestObject.put("app_access_token", this.getAppAccessToken());
requestObject.put("grant_type", "authorization_code");
requestObject.put("code", authCallback.getCode());
return getToken(requestObject, this.source.accessToken());
}
......@@ -57,39 +82,49 @@ public class AuthFeishuRequest extends AuthDefaultRequest {
.add("Content-Type", "application/json")
.add("Authorization", "Bearer " + accessToken), false);
JSONObject object = JSON.parseObject(response);
this.checkResponse(object);
JSONObject data = object.getJSONObject("data");
return AuthUser.builder()
.rawUserInfo(object)
.avatar(object.getString("AvatarUrl"))
.username(object.getString("Mobile"))
.email(object.getString("Email"))
.nickname("Name")
.uuid(data.getString("union_id"))
.username(data.getString("name"))
.nickname(data.getString("name"))
.avatar(data.getString("avatar_url"))
.email(data.getString("email"))
.gender(AuthUserGender.UNKNOWN)
.token(authToken)
.source(source.toString())
.build();
}
@Override
public AuthResponse refresh(AuthToken authToken) {
JSONObject requestObject = new JSONObject();
requestObject.put("app_id", config.getClientId());
requestObject.put("app_secret", config.getClientSecret());
requestObject.put("app_access_token", this.getAppAccessToken());
requestObject.put("grant_type", "refresh_token");
requestObject.put("refresh_token", authToken.getRefreshToken());
String response = new HttpUtils(config.getHttpConfig()).post(source.refresh(), requestObject.toJSONString(), new HttpHeader()
.add("Content-Type", "application/json"));
JSONObject jsonObject = JSON.parseObject(response);
this.checkResponse(jsonObject);
return AuthResponse.builder()
.code(AuthResponseStatus.SUCCESS.getCode())
.data(AuthToken.builder()
.accessToken(jsonObject.getString("access_token"))
.refreshToken(jsonObject.getString("refresh_token"))
.expireIn(jsonObject.getIntValue("expires_in"))
.tokenType(jsonObject.getString("token_type"))
.openId(jsonObject.getString("open_id"))
.build())
.data(getToken(requestObject, this.source.refresh()))
.build();
}
private AuthToken getToken(JSONObject param, String url) {
String response = new HttpUtils(config.getHttpConfig()).post(url, param.toJSONString(), new HttpHeader()
.add("Content-Type", "application/json"));
JSONObject jsonObject = JSON.parseObject(response);
this.checkResponse(jsonObject);
JSONObject data = jsonObject.getJSONObject("data");
return AuthToken.builder()
.accessToken(data.getString("access_token"))
.refreshToken(data.getString("refresh_token"))
.expireIn(data.getIntValue("expires_in"))
.tokenType(data.getString("token_type"))
.openId(data.getString("open_id"))
.build();
}
@Override
public String authorize(String state) {
return UrlBuilder.fromBaseUrl(source.authorize())
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册