简介
- 通常理解的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