Skip to content

Commit 8c7171f

Browse files
author
yanji-yang
committed
fix #69 to Support Web Get JsSdkSignature
1 parent f4fc60a commit 8c7171f

File tree

8 files changed

+287
-59
lines changed

8 files changed

+287
-59
lines changed

larksuite-oapi/src/main/java/com/lark/oapi/Client.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,10 +624,12 @@ private void initCache(Config config) {
624624
if (config.getCache() != null) {
625625
GlobalAppTicketManager.setAppTicketManager(new AppTicketManager(config.getCache()));
626626
GlobalTokenManager.setTokenManager(new TokenManager(config.getCache()));
627+
GlobalJsSdkTicketManager.setGlobalAppTicketManager(new JsSdkTicketManager(config.getCache()));
627628
} else {
628629
ICache cache = LocalCache.getInstance();
629630
GlobalAppTicketManager.setAppTicketManager(new AppTicketManager(cache));
630631
GlobalTokenManager.setTokenManager(new TokenManager(cache));
632+
GlobalJsSdkTicketManager.setGlobalAppTicketManager(new JsSdkTicketManager(cache));
631633
}
632634
}
633635

larksuite-oapi/src/main/java/com/lark/oapi/core/Constants.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,6 @@ public interface Constants {
4343
String GET_AUTHEN_ACCESS_TOKEN = "/open-apis/authen/v1/access_token";
4444
String REFRESH_AUTHEN_ACCESS_TOKEN = "/open-apis/authen/v1/refresh_access_token";
4545
String GET_AUTHEN_USER_INFO = "/open-apis/authen/v1/user_info";
46+
47+
String JS_SDK_TICKET_GET_URL_PATH = "/open-apis/jssdk/ticket/get";
4648
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/*
2+
* MIT License
3+
*
4+
* Copyright (c) 2022 Lark Technologies Pte. Ltd.
5+
*
6+
* 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:
7+
*
8+
* The above copyright notice and this permission notice, shall be included in all copies or substantial portions of the Software.
9+
*
10+
* 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.
11+
*/
12+
13+
package com.lark.oapi.core.token;
14+
15+
import com.lark.oapi.core.cache.LocalCache;
16+
17+
public class GlobalJsSdkTicketManager {
18+
19+
private static volatile JsSdkTicketManager globalAppTicketManager = new JsSdkTicketManager(
20+
LocalCache.getInstance());
21+
22+
public static JsSdkTicketManager getGlobalAppTicketManager() {
23+
return globalAppTicketManager;
24+
}
25+
26+
public static void setGlobalAppTicketManager(JsSdkTicketManager globalAppTicketManager) {
27+
GlobalJsSdkTicketManager.globalAppTicketManager = globalAppTicketManager;
28+
}
29+
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package com.lark.oapi.core.token;
2+
3+
import com.lark.oapi.core.Config;
4+
import com.lark.oapi.core.Constants;
5+
import com.lark.oapi.core.Transport;
6+
import com.lark.oapi.core.cache.ICache;
7+
import com.lark.oapi.core.request.RequestOptions;
8+
import com.lark.oapi.core.response.RawResponse;
9+
import com.lark.oapi.core.utils.Sets;
10+
import com.lark.oapi.core.utils.Strings;
11+
import com.lark.oapi.core.utils.UnmarshalRespUtil;
12+
import com.lark.oapi.service.ext.model.JsSdkTicketResp;
13+
import org.slf4j.Logger;
14+
import org.slf4j.LoggerFactory;
15+
16+
import java.util.concurrent.TimeUnit;
17+
18+
public class JsSdkTicketManager {
19+
20+
private static final Logger log = LoggerFactory.getLogger(TokenManager.class);
21+
private static final int expiryDeltaOfSecond = 3 * 60;
22+
private static final String JS_SDK_TICKET_PREFIX = "js_skd_ticket";
23+
private ICache cache;
24+
25+
public JsSdkTicketManager(ICache cache) {
26+
this.cache = cache;
27+
}
28+
29+
private String getKey(String appId) {
30+
return JS_SDK_TICKET_PREFIX + "-" + appId;
31+
}
32+
33+
public void put(String appId, String value, int expire, TimeUnit timeUnit) {
34+
cache.set(getKey(appId), value, expire, timeUnit);
35+
}
36+
37+
private void getJsSdkTicket(Config config) {
38+
try {
39+
RawResponse resp = Transport.send(config
40+
, RequestOptions.newBuilder().build()
41+
, "POST"
42+
, Constants.JS_SDK_TICKET_GET_URL_PATH
43+
, Sets.newHashSet(AccessTokenType.Tenant), null);
44+
45+
JsSdkTicketResp jsSdkTicketResp = UnmarshalRespUtil.unmarshalResp(resp,
46+
JsSdkTicketResp.class);
47+
48+
String ticket = jsSdkTicketResp.getData().getTicket();
49+
int timeOut = jsSdkTicketResp.getData().getExpiresIn();
50+
put(config.getAppId(), ticket, timeOut - expiryDeltaOfSecond, TimeUnit.SECONDS);
51+
} catch (Exception e) {
52+
log.error("get JsSdkTicket failed ", e);
53+
}
54+
}
55+
56+
public String get(Config config) throws Exception {
57+
String jsSdkTicket = cache.get(getKey(config.getAppId()));
58+
if (Strings.isEmpty(jsSdkTicket)) {
59+
// 触发重新获取
60+
getJsSdkTicket(config);
61+
}
62+
return jsSdkTicket;
63+
}
64+
}

larksuite-oapi/src/main/java/com/lark/oapi/service/ext/ExtService.java

Lines changed: 82 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,14 @@
2020
import com.lark.oapi.core.response.RawResponse;
2121
import com.lark.oapi.core.response.TenantAccessTokenResp;
2222
import com.lark.oapi.core.token.AccessTokenType;
23+
import com.lark.oapi.core.token.GlobalJsSdkTicketManager;
2324
import com.lark.oapi.core.utils.Sets;
2425
import com.lark.oapi.core.utils.UnmarshalRespUtil;
26+
import com.lark.oapi.okio.ByteString;
2527
import com.lark.oapi.service.ext.model.*;
2628

29+
import java.util.UUID;
30+
2731
public class ExtService {
2832

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

4751
CreateFileResp createFileResp = UnmarshalRespUtil.unmarshalResp(resp,
48-
CreateFileResp.class);
52+
CreateFileResp.class);
4953
createFileResp.setRawResponse(resp);
5054
return createFileResp;
5155
}
@@ -60,137 +64,156 @@ public CreateFileResp createFile(CreateFileReq req) throws Exception {
6064
}
6165

6266
public AppAccessTokenResp getAppAccessTokenBySelfBuiltApp(SelfBuiltAppAccessTokenReq req)
63-
throws Exception {
67+
throws Exception {
6468
RawResponse resp = Transport.send(config
65-
, new RequestOptions(), "POST"
66-
, Constants.APP_ACCESS_TOKEN_INTERNAL_URL_PATH
67-
, Sets.newHashSet(AccessTokenType.None), req);
69+
, new RequestOptions(), "POST"
70+
, Constants.APP_ACCESS_TOKEN_INTERNAL_URL_PATH
71+
, Sets.newHashSet(AccessTokenType.None), req);
6872

6973
AppAccessTokenResp appAccessTokenResp = UnmarshalRespUtil.unmarshalResp(resp,
70-
AppAccessTokenResp.class);
74+
AppAccessTokenResp.class);
7175
appAccessTokenResp.setRawResponse(resp);
7276
return appAccessTokenResp;
7377
}
7478

7579
public AppAccessTokenResp getAppAccessTokenByMarketplaceApp(MarketplaceAppAccessTokenReq req)
76-
throws Exception {
80+
throws Exception {
7781
RawResponse resp = Transport.send(config
78-
, new RequestOptions(), "POST"
79-
, Constants.APP_ACCESS_TOKEN_ISV_URL_PATH
80-
, Sets.newHashSet(AccessTokenType.None), req);
82+
, new RequestOptions(), "POST"
83+
, Constants.APP_ACCESS_TOKEN_ISV_URL_PATH
84+
, Sets.newHashSet(AccessTokenType.None), req);
8185

8286
// 结果处理
8387
AppAccessTokenResp appAccessTokenResp = UnmarshalRespUtil.unmarshalResp(resp,
84-
AppAccessTokenResp.class);
88+
AppAccessTokenResp.class);
8589
appAccessTokenResp.setRawResponse(resp);
8690
return appAccessTokenResp;
8791
}
8892

8993
public TenantAccessTokenResp getTenantAccessTokenBySelfBuiltApp(SelfBuiltTenantAccessTokenReq req)
90-
throws Exception {
94+
throws Exception {
9195
RawResponse resp = Transport.send(config
92-
, new RequestOptions(), "POST"
93-
, Constants.TENANT_ACCESS_TOKEN_INTERNAL_URL_PATH
94-
, Sets.newHashSet(AccessTokenType.None), req);
96+
, new RequestOptions(), "POST"
97+
, Constants.TENANT_ACCESS_TOKEN_INTERNAL_URL_PATH
98+
, Sets.newHashSet(AccessTokenType.None), req);
9599

96100
TenantAccessTokenResp tenantAccessTokenResp = UnmarshalRespUtil.unmarshalResp(resp,
97-
TenantAccessTokenResp.class);
101+
TenantAccessTokenResp.class);
98102
tenantAccessTokenResp.setRawResponse(resp);
99103
return tenantAccessTokenResp;
100104
}
101105

102106
public TenantAccessTokenResp getTenantAccessTokenByMarketplaceApp(
103-
MarketplaceTenantAccessTokenReq req)
104-
throws Exception {
107+
MarketplaceTenantAccessTokenReq req)
108+
throws Exception {
105109

106110
RawResponse resp = Transport.send(config
107-
, new RequestOptions(), "POST"
108-
, Constants.TENANT_ACCESS_TOKEN_ISV_URL_PATH
109-
, Sets.newHashSet(AccessTokenType.None), req);
111+
, new RequestOptions(), "POST"
112+
, Constants.TENANT_ACCESS_TOKEN_ISV_URL_PATH
113+
, Sets.newHashSet(AccessTokenType.None), req);
110114

111115
TenantAccessTokenResp tenantAccessTokenResp = UnmarshalRespUtil.unmarshalResp(resp,
112-
TenantAccessTokenResp.class);
116+
TenantAccessTokenResp.class);
113117
tenantAccessTokenResp.setRawResponse(resp);
114118
return tenantAccessTokenResp;
115119
}
116120

117121
public AuthenAccessTokenResp getAuthenAccessToken(
118-
AuthenAccessTokenReq req)
119-
throws Exception {
122+
AuthenAccessTokenReq req)
123+
throws Exception {
120124

121125
RawResponse resp = Transport.send(config
122-
, new RequestOptions(), "POST"
123-
, Constants.GET_AUTHEN_ACCESS_TOKEN
124-
, Sets.newHashSet(AccessTokenType.App), req);
126+
, new RequestOptions(), "POST"
127+
, Constants.GET_AUTHEN_ACCESS_TOKEN
128+
, Sets.newHashSet(AccessTokenType.App), req);
125129

126130
AuthenAccessTokenResp authenAccessTokenResp = UnmarshalRespUtil.unmarshalResp(resp,
127-
AuthenAccessTokenResp.class);
131+
AuthenAccessTokenResp.class);
128132
authenAccessTokenResp.setRawResponse(resp);
129133
return authenAccessTokenResp;
130134
}
131135

132136
public AuthenAccessTokenResp getAuthenAccessToken(
133-
AuthenAccessTokenReq req, RequestOptions requestOptions)
134-
throws Exception {
137+
AuthenAccessTokenReq req, RequestOptions requestOptions)
138+
throws Exception {
135139

136140
RawResponse resp = Transport.send(config
137-
, requestOptions
138-
, "POST"
139-
, Constants.GET_AUTHEN_ACCESS_TOKEN
140-
, Sets.newHashSet(AccessTokenType.App), req);
141+
, requestOptions
142+
, "POST"
143+
, Constants.GET_AUTHEN_ACCESS_TOKEN
144+
, Sets.newHashSet(AccessTokenType.App), req);
141145

142146
AuthenAccessTokenResp authenAccessTokenResp = UnmarshalRespUtil.unmarshalResp(resp,
143-
AuthenAccessTokenResp.class);
147+
AuthenAccessTokenResp.class);
144148
authenAccessTokenResp.setRawResponse(resp);
145149
return authenAccessTokenResp;
146150
}
147151

148152
public RefreshAuthenAccessTokenResp refreshAuthenAccessToken(
149-
RefreshAuthenAccessTokenReq req, RequestOptions requestOptions)
150-
throws Exception {
153+
RefreshAuthenAccessTokenReq req, RequestOptions requestOptions)
154+
throws Exception {
151155

152156
RawResponse resp = Transport.send(config
153-
, requestOptions
154-
, "POST"
155-
, Constants.REFRESH_AUTHEN_ACCESS_TOKEN
156-
, Sets.newHashSet(AccessTokenType.App), req);
157+
, requestOptions
158+
, "POST"
159+
, Constants.REFRESH_AUTHEN_ACCESS_TOKEN
160+
, Sets.newHashSet(AccessTokenType.App), req);
157161

158162
RefreshAuthenAccessTokenResp authenAccessTokenResp = UnmarshalRespUtil.unmarshalResp(resp,
159-
RefreshAuthenAccessTokenResp.class);
163+
RefreshAuthenAccessTokenResp.class);
160164
authenAccessTokenResp.setRawResponse(resp);
161165
return authenAccessTokenResp;
162166
}
163167

164168
public RefreshAuthenAccessTokenResp refreshAuthenAccessToken(
165-
RefreshAuthenAccessTokenReq req)
166-
throws Exception {
169+
RefreshAuthenAccessTokenReq req)
170+
throws Exception {
167171

168172
RawResponse resp = Transport.send(config
169-
, new RequestOptions()
170-
, "POST"
171-
, Constants.REFRESH_AUTHEN_ACCESS_TOKEN
172-
, Sets.newHashSet(AccessTokenType.App), req);
173+
, new RequestOptions()
174+
, "POST"
175+
, Constants.REFRESH_AUTHEN_ACCESS_TOKEN
176+
, Sets.newHashSet(AccessTokenType.App), req);
173177

174178
RefreshAuthenAccessTokenResp authenAccessTokenResp = UnmarshalRespUtil.unmarshalResp(resp,
175-
RefreshAuthenAccessTokenResp.class);
179+
RefreshAuthenAccessTokenResp.class);
176180
authenAccessTokenResp.setRawResponse(resp);
177181
return authenAccessTokenResp;
178182
}
179183

180184
public GetAuthenUserInfoResp getAuthenUserInfo(RequestOptions requestOptions)
181-
throws Exception {
185+
throws Exception {
182186

183187
RawResponse resp = Transport.send(config
184-
, requestOptions
185-
, "GET"
186-
, Constants.GET_AUTHEN_USER_INFO
187-
, Sets.newHashSet(AccessTokenType.User), null);
188+
, requestOptions
189+
, "GET"
190+
, Constants.GET_AUTHEN_USER_INFO
191+
, Sets.newHashSet(AccessTokenType.User), null);
188192

189193
GetAuthenUserInfoResp authenAccessTokenResp = UnmarshalRespUtil.unmarshalResp(resp,
190-
GetAuthenUserInfoResp.class);
194+
GetAuthenUserInfoResp.class);
191195
authenAccessTokenResp.setRawResponse(resp);
192196
return authenAccessTokenResp;
193197
}
194198

199+
public JsSdkSignature getJsSdkSignature(String url)
200+
throws Exception {
201+
return getJsSdkSignature(url, UUID.randomUUID().toString());
202+
}
195203

204+
public JsSdkSignature getJsSdkSignature(String url, String noncestr)
205+
throws Exception {
206+
JsSdkSignature jsSdkSignature = new JsSdkSignature();
207+
String ticket = GlobalJsSdkTicketManager.getGlobalAppTicketManager().get(config);
208+
long timestamp = System.currentTimeMillis();
209+
String verifyStr = String.format("jsapi_ticket=%s&noncestr=%s&timestamp=%d&url=%s", ticket, noncestr, timestamp, url);
210+
String signature = ByteString.encodeUtf8(verifyStr).sha1().hex();
211+
212+
jsSdkSignature.setAppid(config.getAppId());
213+
jsSdkSignature.setTicket(ticket);
214+
jsSdkSignature.setNoncestr(noncestr);
215+
jsSdkSignature.setTimestamp(Long.toString(timestamp));
216+
jsSdkSignature.setSignature(signature);
217+
return jsSdkSignature;
218+
}
196219
}

0 commit comments

Comments
 (0)