1 package com.supwisdom.institute.backend.thirdparty.poa;
3 import java.io.BufferedReader;
4 import java.io.IOException;
5 import java.io.InputStreamReader;
6 import java.io.UnsupportedEncodingException;
7 import java.util.HashMap;
10 import org.apache.commons.lang3.StringUtils;
11 import org.apache.http.HttpHeaders;
12 import org.apache.http.HttpResponse;
13 import org.springframework.beans.factory.annotation.Autowired;
14 import org.springframework.beans.factory.annotation.Value;
15 import org.springframework.data.redis.core.StringRedisTemplate;
16 import org.springframework.scheduling.annotation.Scheduled;
17 import org.springframework.stereotype.Component;
19 import com.alibaba.fastjson.JSONObject;
20 import com.supwisdom.institute.backend.common.core.distributedlock.DistributedLockHandler;
22 import lombok.extern.slf4j.Slf4j;
26 public class PoaUtil {
28 public static void main(String[] args) {
30 PoaUtil.poaServerUrl = "https://poa.supwisdom.com";
31 PoaUtil.clientId = "nV8US9uAdFQ0ovuYpFOloXtFkME=";
32 PoaUtil.clientSecret = "dDgZAzuNnOjfsbm8iDohyVCXBU1GwImeMsmkJzjyGh8=";
33 PoaUtil.scope = "user:v1:readUser,user:v1:readOrganization,user:v1:readGroup,user:v1:readLabel,authz:v1:readRole";
35 //JSONObject accessTokenObject = PoaUtil.getAccessToken("https://poa.supwisdom.com", "tikgr8E6vfcGDXVSG5Vs-00XJoQ=", "wZugRIydkt9lQqJyi7lco-x8wZyyreb41WC_ioj8g-I=", "personalSecurityCenterSa:v1:admin");
36 JSONObject accessTokenObject = PoaUtil.getAccessTokenObject();
37 System.out.println(accessTokenObject.toJSONString());
39 String accessToken = accessTokenObject.getString("access_token");
40 PoaUtil.accessToken = accessToken;
42 JSONObject jsonObject = PoaUtil.loadUserInfoByAccountName("https://poa.supwisdom.com/apis/user/v1", "smartadmin");
43 System.out.println(jsonObject.toJSONString());
48 @Autowired(required = false)
49 private DistributedLockHandler distributedLockHandler;
52 @Scheduled(fixedRate = 3000000)
53 public void refresh() {
54 if (distributedLockHandler == null) {
55 PoaUtil.clearAccessToken();
58 JSONObject accessTokenObject = PoaUtil.getAccessTokenObject();
59 if (PoaUtil.saveAccessToken(accessTokenObject)) {
65 } catch (InterruptedException e) {
68 log.debug("AccessTokenRefresh.refresh retry");
76 final String LOCK_KEY = "poa:ACCESS_TOKEN_REFRESH:LOCK";
78 boolean lock = distributedLockHandler.lock(LOCK_KEY, 5000L); log.debug("AccessTokenRefresh.refresh lock: {}", lock);
83 PoaUtil.clearAccessToken();
86 JSONObject accessTokenObject = PoaUtil.getAccessTokenObject();
88 if (PoaUtil.saveAccessToken(accessTokenObject)) {
92 // 如果 token 获取失败,则 先释放锁,随后再次尝试获取
93 boolean releaseLock = distributedLockHandler.releaseLock(LOCK_KEY); log.debug("AccessTokenRefresh.refresh releaseLock: {}", releaseLock);
97 } catch (InterruptedException e) {
100 log.debug("AccessTokenRefresh.refresh retry");
105 boolean releaseLock = distributedLockHandler.releaseLock(LOCK_KEY); log.debug("AccessTokenRefresh.refresh finally releaseLock: {}", releaseLock);
111 private static String accessToken = null;
114 private static String poaServerUrl;
116 private static String clientId;
118 private static String clientSecret;
120 private static String scope;
122 private static StringRedisTemplate stringRedisTemplate;
124 @Value("${poa.server.url}")
125 public void setPoaServerUrl(String poaServerUrl) {
126 PoaUtil.poaServerUrl = poaServerUrl;
128 @Value("${poa.client.id}")
129 public void setClientId(String clientId) {
130 PoaUtil.clientId = clientId;
132 @Value("${poa.client.secret}")
133 public void setClientSecret(String clientSecret) {
134 PoaUtil.clientSecret = clientSecret;
136 @Value("${poa.scopes}")
137 public void setScopes(String[] scopes) {
138 PoaUtil.scope = StringUtils.join(scopes, ","); log.debug("{}", PoaUtil.scope);
141 @Autowired(required = false)
142 public void setStringRedisTemplate(StringRedisTemplate stringRedisTemplate) {
143 PoaUtil.stringRedisTemplate = stringRedisTemplate;
146 public static boolean saveAccessToken(JSONObject accessTokenObject) {
148 if (accessTokenObject != null) {
149 String accessToken = accessTokenObject.getString("access_token");
150 Long expiresIn = accessTokenObject.getLong("expires_in");
152 PoaUtil.accessToken = accessToken;
154 if (stringRedisTemplate != null) {
155 final String ACCESS_TOKEN_KEY = "poa:"+clientId+":ACCESS_TOKEN";
156 RedisUtils.redisTemplate(stringRedisTemplate).setValue(ACCESS_TOKEN_KEY, expiresIn, accessToken);
165 public static void clearAccessToken() {
166 PoaUtil.accessToken = null;
168 if (stringRedisTemplate != null) {
169 final String ACCESS_TOKEN_KEY = "poa:"+clientId+":ACCESS_TOKEN";
170 RedisUtils.redisTemplate(stringRedisTemplate).expireValue(ACCESS_TOKEN_KEY);
174 public static String getAccessToken() {
175 if (PoaUtil.accessToken != null) {
176 return PoaUtil.accessToken;
179 if (stringRedisTemplate != null) {
180 final String ACCESS_TOKEN_KEY = "poa:"+clientId+":ACCESS_TOKEN";
181 PoaUtil.accessToken = RedisUtils.redisTemplate(stringRedisTemplate).getValue(ACCESS_TOKEN_KEY);
184 return PoaUtil.accessToken;
187 public static JSONObject getAccessTokenObject() {
189 String tokenUrl = poaServerUrl + "/oauth2/token";
191 String grantType = "client_credentials";
193 Map<String, Object> headers = new HashMap<String, Object>();
194 headers.put("Content-Type", "application/x-www-form-urlencoded");
196 String formData = String.format("grant_type=%s&client_id=%s&client_secret=%s&scope=%s", grantType, clientId, clientSecret, scope);
197 //log.debug("Post formData [{}]", formData);
202 HttpResponse httpResponse = HttpUtils.execute(tokenUrl, "POST", null, null, new HashMap<String, Object>(), headers, formData);
205 * "access_token": "0loVdVN4AqPIbStZmkvtkw==",
206 * "token_type": "bearer",
213 * "error": "invalid_client",
214 * "error_description": ""
218 JSONObject resultJsonObject = parseJSONObject(httpResponse);
219 if (resultJsonObject != null) {
220 if (!resultJsonObject.containsKey("error")) {
221 return resultJsonObject;
224 log.error("Get access_token by [{}] from poa error: {}", clientId, resultJsonObject.getString("error"));
229 Thread.sleep(retry * retry * 500L);
230 log.debug("Retry {}", retry);
231 } catch (Exception e) {
233 log.error("Get access_token by [{}] from poa excption: ", clientId, e);
243 private static JSONObject parseJSONObject(HttpResponse httpResponse) {
245 if (httpResponse != null) {
246 StringBuilder entityStringBuilder = new StringBuilder();
248 BufferedReader b = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent(), "UTF-8"), 8*1024);
251 while ((line=b.readLine())!=null) {
252 entityStringBuilder.append(line);
254 log.debug("Fetch response [{}]", entityStringBuilder.toString());
256 JSONObject resultJsonObject = JSONObject.parseObject(entityStringBuilder.toString());
258 return resultJsonObject;
260 } catch (UnsupportedEncodingException e) {
262 } catch (UnsupportedOperationException e) {
264 } catch (IOException e) {
272 public static JSONObject loadUserInfoByAccountName(String baseUrl, String accountName) {
274 String url = baseUrl + "/users/accountName/" + accountName;
276 Map<String, Object> parameters = new HashMap<String, Object>();
278 Map<String, Object> headers = new HashMap<String, Object>();
279 headers.put(HttpHeaders.AUTHORIZATION, "Bearer "+PoaUtil.getAccessToken());
280 log.debug("{}", headers);
282 HttpResponse httpResponse = HttpUtils.execute(url, "GET", parameters, headers);
284 JSONObject resultJsonObject = parseJSONObject(httpResponse);
285 if (resultJsonObject != null) {
286 if (!resultJsonObject.containsKey("error")) {
287 // XXX: 根据API响应数据,须修改为 只返回实际的 data 数据
288 return resultJsonObject;
296 public static JSONObject loadAccountApplicationRoles(String baseUrl, String applicationId, String username) {
298 String url = baseUrl + "/application/"+applicationId+"/account/"+username+"/roles";
301 Map<String, Object> parameters = new HashMap<String, Object>();
302 log.debug("{}", parameters);
304 Map<String, Object> headers = new HashMap<String, Object>();
305 headers.put(HttpHeaders.AUTHORIZATION, "Bearer "+PoaUtil.getAccessToken());
306 log.debug("{}", headers);
308 HttpResponse httpResponse = HttpUtils.execute(url, "GET", parameters, headers);
310 JSONObject resultJsonObject = parseJSONObject(httpResponse);
311 if (resultJsonObject != null) {
312 if (!resultJsonObject.containsKey("error")) {
313 // XXX: 根据API响应数据,须修改为 只返回实际的 data 数据
314 return resultJsonObject;