41f44d69335ae0cdc03632b381384d8ba1562481
[institute/sw-backend.git] /
1 package com.supwisdom.institute.backend.thirdparty.poa;
2
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;
8 import java.util.Map;
9
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;
18
19 import com.alibaba.fastjson.JSONObject;
20 import com.supwisdom.institute.backend.common.core.distributedlock.DistributedLockHandler;
21
22 import lombok.extern.slf4j.Slf4j;
23
24 @Slf4j
25 @Component
26 public class PoaUtil {
27   
28   public static void main(String[] args) {
29     
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";
34     
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());
38     
39     String accessToken = accessTokenObject.getString("access_token");
40     PoaUtil.accessToken = accessToken;
41     
42     JSONObject jsonObject = PoaUtil.loadUserInfoByAccountName("https://poa.supwisdom.com/apis/user/v1", "smartadmin");
43     System.out.println(jsonObject.toJSONString());
44   }
45   
46   
47
48   @Autowired(required = false)
49   private DistributedLockHandler distributedLockHandler;
50   
51   //每隔 3000 秒执行一次
52   @Scheduled(fixedRate = 3000000)
53   public void refresh() {
54     if (distributedLockHandler == null) {
55       PoaUtil.clearAccessToken();
56       
57       try {
58         JSONObject accessTokenObject = PoaUtil.getAccessTokenObject();
59         if (PoaUtil.saveAccessToken(accessTokenObject)) {
60           return;
61         }
62         
63         try {
64           Thread.sleep(500L);
65         } catch (InterruptedException e) {
66           e.printStackTrace();
67         }
68         log.debug("AccessTokenRefresh.refresh retry");
69         
70         refresh();
71       } finally {
72         
73       }
74     }
75     
76     final String LOCK_KEY = "poa:ACCESS_TOKEN_REFRESH:LOCK";
77     
78     boolean lock = distributedLockHandler.lock(LOCK_KEY, 5000L);  log.debug("AccessTokenRefresh.refresh lock: {}", lock);
79     if(!lock) {
80       return;
81     }
82
83     PoaUtil.clearAccessToken();
84
85     try {
86       JSONObject accessTokenObject = PoaUtil.getAccessTokenObject();
87       
88       if (PoaUtil.saveAccessToken(accessTokenObject)) {
89         return;
90       }
91       
92       // 如果 token 获取失败,则 先释放锁,随后再次尝试获取
93       boolean releaseLock = distributedLockHandler.releaseLock(LOCK_KEY);  log.debug("AccessTokenRefresh.refresh releaseLock: {}", releaseLock);
94       
95       try {
96         Thread.sleep(500L);
97       } catch (InterruptedException e) {
98         e.printStackTrace();
99       }
100       log.debug("AccessTokenRefresh.refresh retry");
101       
102       refresh();
103       
104     } finally {
105       boolean releaseLock = distributedLockHandler.releaseLock(LOCK_KEY);  log.debug("AccessTokenRefresh.refresh finally releaseLock: {}", releaseLock);
106     }
107     
108   }
109
110   
111   private static String accessToken = null;
112   
113   
114   private static String poaServerUrl;
115
116   private static String clientId;
117
118   private static String clientSecret;
119
120   private static String scope;
121   
122   private static StringRedisTemplate stringRedisTemplate;
123
124   @Value("${poa.server.url}")
125   public void setPoaServerUrl(String poaServerUrl) {
126     PoaUtil.poaServerUrl = poaServerUrl;
127   }
128   @Value("${poa.client.id}")
129   public void setClientId(String clientId) {
130     PoaUtil.clientId = clientId;
131   }
132   @Value("${poa.client.secret}")
133   public void setClientSecret(String clientSecret) {
134     PoaUtil.clientSecret = clientSecret;
135   }
136   @Value("${poa.scopes}")
137   public void setScopes(String[] scopes) {
138     PoaUtil.scope = StringUtils.join(scopes, ","); log.debug("{}", PoaUtil.scope);
139   }
140   
141   @Autowired(required = false)
142   public void setStringRedisTemplate(StringRedisTemplate stringRedisTemplate) {
143     PoaUtil.stringRedisTemplate = stringRedisTemplate;
144   }
145   
146   public static boolean saveAccessToken(JSONObject accessTokenObject) {
147     
148     if (accessTokenObject != null) {
149       String accessToken = accessTokenObject.getString("access_token");
150       Long expiresIn = accessTokenObject.getLong("expires_in");
151       
152       PoaUtil.accessToken = accessToken;
153       
154       if (stringRedisTemplate != null) {
155         final String ACCESS_TOKEN_KEY = "poa:"+clientId+":ACCESS_TOKEN";
156         RedisUtils.redisTemplate(stringRedisTemplate).setValue(ACCESS_TOKEN_KEY, expiresIn, accessToken);
157       }
158       
159       return true;
160     }
161     
162     return false;
163   }
164   
165   public static void clearAccessToken() {
166     PoaUtil.accessToken = null;
167
168     if (stringRedisTemplate != null) {
169       final String ACCESS_TOKEN_KEY = "poa:"+clientId+":ACCESS_TOKEN";
170       RedisUtils.redisTemplate(stringRedisTemplate).expireValue(ACCESS_TOKEN_KEY);
171     }
172   }
173   
174   public static String getAccessToken() {
175     if (PoaUtil.accessToken != null) {
176       return PoaUtil.accessToken;
177     }
178     
179     if (stringRedisTemplate != null) {
180       final String ACCESS_TOKEN_KEY = "poa:"+clientId+":ACCESS_TOKEN";
181       PoaUtil.accessToken = RedisUtils.redisTemplate(stringRedisTemplate).getValue(ACCESS_TOKEN_KEY);
182     }
183     
184     return PoaUtil.accessToken;
185   }
186   
187   public static JSONObject getAccessTokenObject() {
188     
189     String tokenUrl = poaServerUrl + "/oauth2/token";
190     
191     String grantType = "client_credentials";
192     
193     Map<String, Object> headers = new HashMap<String, Object>();
194     headers.put("Content-Type", "application/x-www-form-urlencoded");
195     
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);
198
199     int retry = 0;
200     while(retry < 3) {
201       try{
202         HttpResponse httpResponse = HttpUtils.execute(tokenUrl, "POST", null, null, new HashMap<String, Object>(), headers, formData);
203         /**
204          * {
205          *   "access_token": "0loVdVN4AqPIbStZmkvtkw==",
206          *   "token_type": "bearer",
207          *   "expires_in": 3600
208          * }
209          */
210         
211         /**
212          * {
213          *   "error": "invalid_client",
214          *   "error_description": ""
215          * }
216          */
217         
218         JSONObject resultJsonObject = parseJSONObject(httpResponse);
219         if (resultJsonObject != null) {
220           if (!resultJsonObject.containsKey("error")) {
221             return resultJsonObject;
222           }
223           
224           log.error("Get access_token by [{}] from poa error: {}", clientId, resultJsonObject.getString("error"));
225           break;
226         }
227         
228         retry ++;
229         Thread.sleep(retry * retry * 500L);
230         log.debug("Retry {}", retry);
231       } catch (Exception e) {
232         // 未知异常时,重试
233         log.error("Get access_token by [{}] from poa excption: ", clientId, e);
234       }
235
236     }
237     
238     return null;
239   }
240   
241   
242
243   private static JSONObject parseJSONObject(HttpResponse httpResponse) {
244     try {
245       if (httpResponse != null) {
246         StringBuilder entityStringBuilder = new StringBuilder();
247   
248         BufferedReader b = new BufferedReader(new InputStreamReader(httpResponse.getEntity().getContent(), "UTF-8"), 8*1024);
249   
250         String line=null;
251         while ((line=b.readLine())!=null) {
252           entityStringBuilder.append(line);
253         }
254         log.debug("Fetch response [{}]", entityStringBuilder.toString());
255         
256         JSONObject resultJsonObject = JSONObject.parseObject(entityStringBuilder.toString());
257         
258         return resultJsonObject;
259       }
260     } catch (UnsupportedEncodingException e) {
261       e.printStackTrace();
262     } catch (UnsupportedOperationException e) {
263       e.printStackTrace();
264     } catch (IOException e) {
265       e.printStackTrace();
266     }
267     
268     return null;
269   }
270   
271   
272   public static JSONObject loadUserInfoByAccountName(String baseUrl, String accountName) {
273     
274     String url = baseUrl + "/users/accountName/" + accountName;
275
276     Map<String, Object> parameters = new HashMap<String, Object>();
277
278     Map<String, Object> headers = new HashMap<String, Object>();
279     headers.put(HttpHeaders.AUTHORIZATION, "Bearer "+PoaUtil.getAccessToken());
280     log.debug("{}", headers);
281     
282     HttpResponse httpResponse = HttpUtils.execute(url, "GET", parameters, headers);
283     
284     JSONObject resultJsonObject = parseJSONObject(httpResponse);
285     if (resultJsonObject != null) {
286       if (!resultJsonObject.containsKey("error")) {
287         // XXX: 根据API响应数据,须修改为 只返回实际的 data 数据
288         return resultJsonObject;
289       }
290     }
291     
292     return null;
293   }
294   
295   
296   public static JSONObject loadAccountApplicationRoles(String baseUrl, String applicationId, String username) {
297     
298     String url = baseUrl + "/application/"+applicationId+"/account/"+username+"/roles";
299     log.debug(url);
300     
301     Map<String, Object> parameters = new HashMap<String, Object>();
302     log.debug("{}", parameters);
303
304     Map<String, Object> headers = new HashMap<String, Object>();
305     headers.put(HttpHeaders.AUTHORIZATION, "Bearer "+PoaUtil.getAccessToken());
306     log.debug("{}", headers);
307     
308     HttpResponse httpResponse = HttpUtils.execute(url, "GET", parameters, headers);
309     
310     JSONObject resultJsonObject = parseJSONObject(httpResponse);
311     if (resultJsonObject != null) {
312       if (!resultJsonObject.containsKey("error")) {
313         // XXX: 根据API响应数据,须修改为 只返回实际的 data 数据
314         return resultJsonObject;
315       }
316     }
317     
318     return null;
319   }
320   
321 }