Skip to content

fix #69 to Support Web Get JsSdkSignature #102

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: v2_main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions larksuite-oapi/src/main/java/com/lark/oapi/Client.java
Original file line number Diff line number Diff line change
@@ -624,10 +624,12 @@ private void initCache(Config config) {
if (config.getCache() != null) {
GlobalAppTicketManager.setAppTicketManager(new AppTicketManager(config.getCache()));
GlobalTokenManager.setTokenManager(new TokenManager(config.getCache()));
GlobalJsSdkTicketManager.setGlobalAppTicketManager(new JsSdkTicketManager(config.getCache()));
} else {
ICache cache = LocalCache.getInstance();
GlobalAppTicketManager.setAppTicketManager(new AppTicketManager(cache));
GlobalTokenManager.setTokenManager(new TokenManager(cache));
GlobalJsSdkTicketManager.setGlobalAppTicketManager(new JsSdkTicketManager(cache));
}
}

Original file line number Diff line number Diff line change
@@ -43,4 +43,6 @@ public interface Constants {
String GET_AUTHEN_ACCESS_TOKEN = "/open-apis/authen/v1/access_token";
String REFRESH_AUTHEN_ACCESS_TOKEN = "/open-apis/authen/v1/refresh_access_token";
String GET_AUTHEN_USER_INFO = "/open-apis/authen/v1/user_info";

String JS_SDK_TICKET_GET_URL_PATH = "/open-apis/jssdk/ticket/get";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* MIT License
*
* Copyright (c) 2022 Lark Technologies Pte. Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice, shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

package com.lark.oapi.core.token;

import com.lark.oapi.core.cache.LocalCache;

public class GlobalJsSdkTicketManager {

private static volatile JsSdkTicketManager globalAppTicketManager = new JsSdkTicketManager(
LocalCache.getInstance());

public static JsSdkTicketManager getGlobalAppTicketManager() {
return globalAppTicketManager;
}

public static void setGlobalAppTicketManager(JsSdkTicketManager globalAppTicketManager) {
GlobalJsSdkTicketManager.globalAppTicketManager = globalAppTicketManager;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.lark.oapi.core.token;

import com.lark.oapi.core.Config;
import com.lark.oapi.core.Constants;
import com.lark.oapi.core.Transport;
import com.lark.oapi.core.cache.ICache;
import com.lark.oapi.core.request.RequestOptions;
import com.lark.oapi.core.response.RawResponse;
import com.lark.oapi.core.utils.Sets;
import com.lark.oapi.core.utils.Strings;
import com.lark.oapi.core.utils.UnmarshalRespUtil;
import com.lark.oapi.service.ext.model.JsSdkTicketResp;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.TimeUnit;

public class JsSdkTicketManager {

private static final Logger log = LoggerFactory.getLogger(TokenManager.class);
private static final int expiryDeltaOfSecond = 3 * 60;
private static final String JS_SDK_TICKET_PREFIX = "js_skd_ticket";
private ICache cache;

public JsSdkTicketManager(ICache cache) {
this.cache = cache;
}

private String getKey(String appId) {
return JS_SDK_TICKET_PREFIX + "-" + appId;
}

public void put(String appId, String value, int expire, TimeUnit timeUnit) {
cache.set(getKey(appId), value, expire, timeUnit);
}

private void getJsSdkTicket(Config config) {
try {
RawResponse resp = Transport.send(config
, RequestOptions.newBuilder().build()
, "POST"
, Constants.JS_SDK_TICKET_GET_URL_PATH
, Sets.newHashSet(AccessTokenType.Tenant), null);

JsSdkTicketResp jsSdkTicketResp = UnmarshalRespUtil.unmarshalResp(resp,
JsSdkTicketResp.class);

String ticket = jsSdkTicketResp.getData().getTicket();
int timeOut = jsSdkTicketResp.getData().getExpiresIn();
put(config.getAppId(), ticket, timeOut - expiryDeltaOfSecond, TimeUnit.SECONDS);
} catch (Exception e) {
log.error("get JsSdkTicket failed ", e);
}
}

public String get(Config config) throws Exception {
String jsSdkTicket = cache.get(getKey(config.getAppId()));
if (Strings.isEmpty(jsSdkTicket)) {
// 触发重新获取
getJsSdkTicket(config);
}
return jsSdkTicket;
}
}
141 changes: 82 additions & 59 deletions larksuite-oapi/src/main/java/com/lark/oapi/service/ext/ExtService.java
Original file line number Diff line number Diff line change
@@ -20,10 +20,14 @@
import com.lark.oapi.core.response.RawResponse;
import com.lark.oapi.core.response.TenantAccessTokenResp;
import com.lark.oapi.core.token.AccessTokenType;
import com.lark.oapi.core.token.GlobalJsSdkTicketManager;
import com.lark.oapi.core.utils.Sets;
import com.lark.oapi.core.utils.UnmarshalRespUtil;
import com.lark.oapi.okio.ByteString;
import com.lark.oapi.service.ext.model.*;

import java.util.UUID;

public class ExtService {

private Config config;
@@ -38,14 +42,14 @@ public ExtService(Config config) {
link: https://open.feishu.cn/document/ukTMukTMukTM/uQTNzUjL0UzM14CN1MTN
*/
public CreateFileResp createFile(CreateFileReq req, RequestOptions requestOptions)
throws Exception {
throws Exception {
RawResponse resp = Transport.send(config
, requestOptions, "POST"
, "/open-apis/drive/explorer/v2/file/:folderToken"
, Sets.newHashSet(AccessTokenType.Tenant, AccessTokenType.User), req);
, requestOptions, "POST"
, "/open-apis/drive/explorer/v2/file/:folderToken"
, Sets.newHashSet(AccessTokenType.Tenant, AccessTokenType.User), req);

CreateFileResp createFileResp = UnmarshalRespUtil.unmarshalResp(resp,
CreateFileResp.class);
CreateFileResp.class);
createFileResp.setRawResponse(resp);
return createFileResp;
}
@@ -60,137 +64,156 @@ public CreateFileResp createFile(CreateFileReq req) throws Exception {
}

public AppAccessTokenResp getAppAccessTokenBySelfBuiltApp(SelfBuiltAppAccessTokenReq req)
throws Exception {
throws Exception {
RawResponse resp = Transport.send(config
, new RequestOptions(), "POST"
, Constants.APP_ACCESS_TOKEN_INTERNAL_URL_PATH
, Sets.newHashSet(AccessTokenType.None), req);
, new RequestOptions(), "POST"
, Constants.APP_ACCESS_TOKEN_INTERNAL_URL_PATH
, Sets.newHashSet(AccessTokenType.None), req);

AppAccessTokenResp appAccessTokenResp = UnmarshalRespUtil.unmarshalResp(resp,
AppAccessTokenResp.class);
AppAccessTokenResp.class);
appAccessTokenResp.setRawResponse(resp);
return appAccessTokenResp;
}

public AppAccessTokenResp getAppAccessTokenByMarketplaceApp(MarketplaceAppAccessTokenReq req)
throws Exception {
throws Exception {
RawResponse resp = Transport.send(config
, new RequestOptions(), "POST"
, Constants.APP_ACCESS_TOKEN_ISV_URL_PATH
, Sets.newHashSet(AccessTokenType.None), req);
, new RequestOptions(), "POST"
, Constants.APP_ACCESS_TOKEN_ISV_URL_PATH
, Sets.newHashSet(AccessTokenType.None), req);

// 结果处理
AppAccessTokenResp appAccessTokenResp = UnmarshalRespUtil.unmarshalResp(resp,
AppAccessTokenResp.class);
AppAccessTokenResp.class);
appAccessTokenResp.setRawResponse(resp);
return appAccessTokenResp;
}

public TenantAccessTokenResp getTenantAccessTokenBySelfBuiltApp(SelfBuiltTenantAccessTokenReq req)
throws Exception {
throws Exception {
RawResponse resp = Transport.send(config
, new RequestOptions(), "POST"
, Constants.TENANT_ACCESS_TOKEN_INTERNAL_URL_PATH
, Sets.newHashSet(AccessTokenType.None), req);
, new RequestOptions(), "POST"
, Constants.TENANT_ACCESS_TOKEN_INTERNAL_URL_PATH
, Sets.newHashSet(AccessTokenType.None), req);

TenantAccessTokenResp tenantAccessTokenResp = UnmarshalRespUtil.unmarshalResp(resp,
TenantAccessTokenResp.class);
TenantAccessTokenResp.class);
tenantAccessTokenResp.setRawResponse(resp);
return tenantAccessTokenResp;
}

public TenantAccessTokenResp getTenantAccessTokenByMarketplaceApp(
MarketplaceTenantAccessTokenReq req)
throws Exception {
MarketplaceTenantAccessTokenReq req)
throws Exception {

RawResponse resp = Transport.send(config
, new RequestOptions(), "POST"
, Constants.TENANT_ACCESS_TOKEN_ISV_URL_PATH
, Sets.newHashSet(AccessTokenType.None), req);
, new RequestOptions(), "POST"
, Constants.TENANT_ACCESS_TOKEN_ISV_URL_PATH
, Sets.newHashSet(AccessTokenType.None), req);

TenantAccessTokenResp tenantAccessTokenResp = UnmarshalRespUtil.unmarshalResp(resp,
TenantAccessTokenResp.class);
TenantAccessTokenResp.class);
tenantAccessTokenResp.setRawResponse(resp);
return tenantAccessTokenResp;
}

public AuthenAccessTokenResp getAuthenAccessToken(
AuthenAccessTokenReq req)
throws Exception {
AuthenAccessTokenReq req)
throws Exception {

RawResponse resp = Transport.send(config
, new RequestOptions(), "POST"
, Constants.GET_AUTHEN_ACCESS_TOKEN
, Sets.newHashSet(AccessTokenType.App), req);
, new RequestOptions(), "POST"
, Constants.GET_AUTHEN_ACCESS_TOKEN
, Sets.newHashSet(AccessTokenType.App), req);

AuthenAccessTokenResp authenAccessTokenResp = UnmarshalRespUtil.unmarshalResp(resp,
AuthenAccessTokenResp.class);
AuthenAccessTokenResp.class);
authenAccessTokenResp.setRawResponse(resp);
return authenAccessTokenResp;
}

public AuthenAccessTokenResp getAuthenAccessToken(
AuthenAccessTokenReq req, RequestOptions requestOptions)
throws Exception {
AuthenAccessTokenReq req, RequestOptions requestOptions)
throws Exception {

RawResponse resp = Transport.send(config
, requestOptions
, "POST"
, Constants.GET_AUTHEN_ACCESS_TOKEN
, Sets.newHashSet(AccessTokenType.App), req);
, requestOptions
, "POST"
, Constants.GET_AUTHEN_ACCESS_TOKEN
, Sets.newHashSet(AccessTokenType.App), req);

AuthenAccessTokenResp authenAccessTokenResp = UnmarshalRespUtil.unmarshalResp(resp,
AuthenAccessTokenResp.class);
AuthenAccessTokenResp.class);
authenAccessTokenResp.setRawResponse(resp);
return authenAccessTokenResp;
}

public RefreshAuthenAccessTokenResp refreshAuthenAccessToken(
RefreshAuthenAccessTokenReq req, RequestOptions requestOptions)
throws Exception {
RefreshAuthenAccessTokenReq req, RequestOptions requestOptions)
throws Exception {

RawResponse resp = Transport.send(config
, requestOptions
, "POST"
, Constants.REFRESH_AUTHEN_ACCESS_TOKEN
, Sets.newHashSet(AccessTokenType.App), req);
, requestOptions
, "POST"
, Constants.REFRESH_AUTHEN_ACCESS_TOKEN
, Sets.newHashSet(AccessTokenType.App), req);

RefreshAuthenAccessTokenResp authenAccessTokenResp = UnmarshalRespUtil.unmarshalResp(resp,
RefreshAuthenAccessTokenResp.class);
RefreshAuthenAccessTokenResp.class);
authenAccessTokenResp.setRawResponse(resp);
return authenAccessTokenResp;
}

public RefreshAuthenAccessTokenResp refreshAuthenAccessToken(
RefreshAuthenAccessTokenReq req)
throws Exception {
RefreshAuthenAccessTokenReq req)
throws Exception {

RawResponse resp = Transport.send(config
, new RequestOptions()
, "POST"
, Constants.REFRESH_AUTHEN_ACCESS_TOKEN
, Sets.newHashSet(AccessTokenType.App), req);
, new RequestOptions()
, "POST"
, Constants.REFRESH_AUTHEN_ACCESS_TOKEN
, Sets.newHashSet(AccessTokenType.App), req);

RefreshAuthenAccessTokenResp authenAccessTokenResp = UnmarshalRespUtil.unmarshalResp(resp,
RefreshAuthenAccessTokenResp.class);
RefreshAuthenAccessTokenResp.class);
authenAccessTokenResp.setRawResponse(resp);
return authenAccessTokenResp;
}

public GetAuthenUserInfoResp getAuthenUserInfo(RequestOptions requestOptions)
throws Exception {
throws Exception {

RawResponse resp = Transport.send(config
, requestOptions
, "GET"
, Constants.GET_AUTHEN_USER_INFO
, Sets.newHashSet(AccessTokenType.User), null);
, requestOptions
, "GET"
, Constants.GET_AUTHEN_USER_INFO
, Sets.newHashSet(AccessTokenType.User), null);

GetAuthenUserInfoResp authenAccessTokenResp = UnmarshalRespUtil.unmarshalResp(resp,
GetAuthenUserInfoResp.class);
GetAuthenUserInfoResp.class);
authenAccessTokenResp.setRawResponse(resp);
return authenAccessTokenResp;
}

public JsSdkSignature getJsSdkSignature(String url)
throws Exception {
return getJsSdkSignature(url, UUID.randomUUID().toString());
}

public JsSdkSignature getJsSdkSignature(String url, String noncestr)
throws Exception {
JsSdkSignature jsSdkSignature = new JsSdkSignature();
String ticket = GlobalJsSdkTicketManager.getGlobalAppTicketManager().get(config);
long timestamp = System.currentTimeMillis();
String verifyStr = String.format("jsapi_ticket=%s&noncestr=%s&timestamp=%d&url=%s", ticket, noncestr, timestamp, url);
String signature = ByteString.encodeUtf8(verifyStr).sha1().hex();

jsSdkSignature.setAppid(config.getAppId());
jsSdkSignature.setTicket(ticket);
jsSdkSignature.setNoncestr(noncestr);
jsSdkSignature.setTimestamp(Long.toString(timestamp));
jsSdkSignature.setSignature(signature);
return jsSdkSignature;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package com.lark.oapi.service.ext.model;

public class JsSdkSignature {

private String appid;

private String ticket;

private String signature;

private String noncestr;

private String timestamp;

public String getAppid() {
return appid;
}

public void setAppid(String appid) {
this.appid = appid;
}

public String getTicket() {
return ticket;
}

public void setTicket(String ticket) {
this.ticket = ticket;
}

public String getSignature() {
return signature;
}

public void setSignature(String signature) {
this.signature = signature;
}

public String getNoncestr() {
return noncestr;
}

public void setNoncestr(String noncestr) {
this.noncestr = noncestr;
}

public String getTimestamp() {
return timestamp;
}

public void setTimestamp(String timestamp) {
this.timestamp = timestamp;
}

@Override
public String toString() {
return "JsSdkSignature{" +
"appid='" + appid + '\'' +
", ticket='" + ticket + '\'' +
", signature='" + signature + '\'' +
", noncestr='" + noncestr + '\'' +
", timestamp='" + timestamp + '\'' +
'}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package com.lark.oapi.service.ext.model;

import com.google.gson.annotations.SerializedName;

public class JsSdkTicket {

@SerializedName("expires_in")
private Integer expiresIn;

@SerializedName("ticket")
private String ticket;

public Integer getExpiresIn() {
return expiresIn;
}

public void setExpiresIn(Integer expiresIn) {
this.expiresIn = expiresIn;
}

public String getTicket() {
return ticket;
}

public void setTicket(String ticket) {
this.ticket = ticket;
}

@Override
public String toString() {
return "JsSdkTicket{" +
"expiresIn=" + expiresIn +
", ticket='" + ticket + '\'' +
'}';
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.lark.oapi.service.ext.model;

import com.lark.oapi.core.response.BaseResponse;

public class JsSdkTicketResp extends BaseResponse<JsSdkTicket> {

}