簡介
- 通常理解的access_token和refresh_token
access_token
是用來對客戶端進行認證的,類似與密碼,有一定的有效期。當過期后可使用refresh_token
重新獲取一個新的access_token。refresh_token的有效期相對較長
- 微信開發設置到兩種access_token
- 第一種是
接口授權access_token
,是用來調用微信高級接口的,有次數限制,是來區分公眾號的 - 另外一種是
用戶授權access_token
,是用戶授權公眾號獲取用戶信息是得到的,無次數限制,使用用來區分用戶的(一般用在微信H5開發上)
- 第一種是
- 由於上述第一種access_token是有次數限制的,因此我們需要將太緩存(保存)起來,每次調用接口的時候先取我們緩存的access_token,而不是從新獲取一個新的access_token。
- 由於refresh_token的有效期相對較長,且使用頻率較少,此處只說明access_token的保存(refresh_token可類似處理)
使用redis保存access_token
- 微信公眾平台API每日有調用上限,即使某些公眾號或服務號有清零某些接口調用的次數權限,但也架不住濫用或錯誤的調用,官方建議access_token由一台服務來維護和提供查詢功能,另外特別重要的一點是每個憑證都擁有生命周期,長短不同,access_token的生命周期是7200秒,在這段時間內可以重復使用,所以不要在每使用一次憑證就重新獲取一個access_token了。
- 通常會保存在內存數據庫中,如Redis,當然也可以直接放在應用程序的內存中,不建議放在oracle或MySQL,拿取開銷較比其它手段太重。放在內存數據庫中的好處較比放在應用程序的內存中是維護性好,尤其是搭配了可視化管理工具后。另外不僅可以放access_token,也可以其它數據庫。[^1] [^2]
-
示例(基於springboot)
-
redis等其他基礎配置省略
-
application.yml
其中myapp下的key都需要進行自定義參數配置,此處也存儲了用戶授權access_tokenmyapp: redisWxUserAccessToken: "user.wxUserAccessToken" redisWxUserRefreshToken: "user.wxUserRefreshToken" redisWxAccessToken: "sys.wxAccessToken" redisWxRefreshToken: "sys.wxRefreshToken"
-
此處以保存用戶授權access_token為例,接口調用access_token可在項目啟動時進行緩存。部分代碼如下:
@Autowired private RedisTemplate<String, String> redisTemplate; @Value("${myapp.redisWxUserAccessToken}") private String redisWxUserAccessToken; // 獲取 public String getUserAccessToken(Object userId) { String accessToken = null; if(StringUtils.isEmpty(userId)) return accessToken; String accessTokenStr = (String) redisTemplate.opsForHash().get(redisWxUserAccessToken, String.valueOf(userId)); long now = (new Date()).getTime(); if(!StringUtils.isEmpty(accessTokenStr)) { String[] arr = accessTokenStr.split("#"); if(now < Long.valueOf(arr[1])) { accessToken = arr[0]; } } if(StringUtils.isEmpty(accessToken)) { accessToken = getUserAccessTokenByRefreshToken(userId); } return accessToken; } // 重新獲取 Object expiresIn = accessTokenMap.get("expires_in"); // 調用微信授權接口后,返回的expires_in參數 String value = accessTokenNew + "#" + getNowExpiresIn(expiresIn); // 此處是設置有效期 redisTemplate.opsForHash().put(redisWxUserAccessToken, String.valueOf(userId), value); public Long getNowExpiresIn(Object expiresIn) { long now = (new Date()).getTime(); if(expiresIn == null) return now; Long expiresMs = Long.valueOf(String.valueOf(expiresIn)) - 15 * 60; return expiresMs * 1000 + now; }
-
[^1] 網頁授權的access_token大家是怎么緩存的
[^2] https://segmentfault.com/q/1010000004995599/a-1020000005016398