获取 accesstoken

原理介绍

概述

access_token 是公众号的全局唯一接口调用凭据,公众号调用接口时都需使用 access_token。开发者需要进行妥善保存。access_token 的存储至少要保留 512 个字符空间access_token 的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的 access_token 失效。

公众平台的API调用所需的 access_token 的使用及生成方式说明:

1、建议公众号开发者使用中控服务器统一获取和刷新 access_token,其他业务逻辑服务器所使用的access_token 均来自于该中控服务器,不应该各自去刷新,否则容易造成冲突,导致 access_token 覆盖而影响业务;

2、目前 access_token 的有效期通过返回的 expire_in 来传达,目前是 7200 秒之内的值。中控服务器需要根据这个有效时间提前去刷新新 access_token。在刷新过程中,中控服务器可对外继续输出的老 access_token,此时公众平台后台会保证在5分钟内,新老 access_token都可用,这保证了第三方业务的平滑过渡;

3、access_token 的有效时间可能会在未来有调整,所以中控服务器不仅需要内部定时主动刷新,还需要提供被动刷新 access_token 的接口,这样便于业务服务器在API调用获知 access_token 已超时的情况下,可以触发access_token 的刷新流程。

公众号和小程序均可以使用 AppId 和 AppSecret 调用本接口来获取 access_token。AppId 和 AppSecret 可在“微信公众平台-开发-基本配置”页中获得(需要已经成为开发者,且帐号没有异常状态)。调用接口时,请登录“微信公众平台-开发-基本配置”提前将服务器 IP 地址添加到 IP 白名单中,否则将无法调用成功。 小程序无需配置IP白名单。

以上内容来自 官方文档获取 accesstoken - 图1

划重点

  • 调用 access_token 接口需要在微信公众平台配置 IP 白名单
  • access_token 有效期为 7200 秒
  • 可以提前刷新 access_token ,此时公众平台后台会保证在5分钟内新老 access_token 都可用
  • 以上策略同时适用于微信公众号、企业微信、微信小程序、微信小游戏

TNWX 中实现方案

TNWX AccessToken 模块源码获取 accesstoken - 图2

  1. export class AccessTokenApi {
  2. private static url: string = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s";
  3. /**
  4. * 获取 acces_token
  5. * 1、先从缓存中获取,如果可用就直接返回
  6. * 2、如果缓存中的已过期就调用刷新接口来获取新的 acces_token
  7. */
  8. public static async getAccessToken() {
  9. let ac: ApiConfig = ApiConfigKit.getApiConfig;
  10. let accessToken: AccessToken | undefined = this.getAvailableAccessToken(ac);
  11. if (accessToken) {
  12. if(ApiConfigKit.isDevMode) console.log("缓存中的 accesstoken");
  13. return accessToken;
  14. }
  15. if(ApiConfigKit.isDevMode) console.log("刷新 accesstoken");
  16. return await this.refreshAccessToken(ac);;
  17. }
  18. /**
  19. * 通过 appId 从缓存中获取 acces_token
  20. * @param apiConfig
  21. */
  22. private static getAvailableAccessToken(apiConfig: ApiConfig): AccessToken | undefined {
  23. let result: AccessToken | undefined;
  24. let accessTokenCache: ICache = ApiConfigKit.getAccessTokenCache;
  25. let accessTokenJson: string = accessTokenCache.get(apiConfig.getAppId);
  26. if (accessTokenJson) {
  27. result = new AccessToken(accessTokenJson);
  28. }
  29. if (result && result.isAvailable()) {
  30. return result;
  31. } else {
  32. return undefined;
  33. }
  34. }
  35. /**
  36. * 获取新的 acces_token 并设置缓存
  37. * @param apiConfig
  38. */
  39. public static async refreshAccessToken(apiConfig: ApiConfig) {
  40. let url = util.format(this.url, apiConfig.getAppId, apiConfig.getAppScrect);
  41. let data = await HttpKit.getHttpDelegate.httpGet(url);
  42. if (data) {
  43. let accessToken: AccessToken = new AccessToken(data)
  44. let accessTokenCache: ICache = ApiConfigKit.getAccessTokenCache;
  45. accessTokenCache.set(apiConfig.getAppId, accessToken.getCacheJson);
  46. return accessToken;
  47. } else {
  48. new Error("获取accessToken异常");
  49. }
  50. }
  51. }

总结

默认 access_token 缓存在内存中,但这有一个缺点,当应用关闭后又得重新获取。所以 TNWX 中提供了设置缓存的扩展。

缓存扩展

access_token 缓存接口 ICache

  1. export interface ICache {
  2. get(key: string): string;
  3. set(key: string, jsonValue: string): void;
  4. remove(key: string): void;
  5. }

默认实现 DefaultCache

  1. export class DefaultCache implements ICache {
  2. private map: Map<string, string> = new Map<string, string>();
  3. get(key: string): string {
  4. return this.map.get(key) || '';
  5. }
  6. set(key: string, jsonValue: string) {
  7. this.map.set(key, jsonValue);
  8. }
  9. remove(key: string) {
  10. this.map.delete(key);
  11. }
  12. }

如何使用?

  1. // 获取access_token
  2. app.get('/getAccessToken', (req: any, res: any) => {
  3. AccessTokenApi.getAccessToken()
  4. .then(data => {
  5. let accessToken = <AccessToken>data;
  6. res.send(accessToken);
  7. });
  8. });

如何刷新?

  1. AccessTokenApi.refreshAccessToken(ApiConfigKit.getApiConfig);

替换默认缓存策略

DefaultCache 替换为你的实现类即可 比如:缓存至文件、Redis 等

  1. ApiConfigKit.setCache = new DefaultCache();

企业微信

实现原理与微信公众号相同

  1. app.get('/getQyAccessToken', (req: any, res: any) => {
  2. QyAccessTokenApi.getAccessToken()
  3. .then(data => {
  4. let accessToken = <AccessToken>data;
  5. res.send(accessToken);
  6. })
  7. .catch((error) => console.log(error));
  8. });
  1. QyAccessTokenApi.refreshAccessToken(QyApiConfigKit.getApiConfig);

企业微信开发平台

获取服务商凭证

获取服务商凭证 provider_access_token

  1. OpenCpAccessTokenApi.getAccessToken(AccessTokenType.PROVIDER_TOKEN)

获取第三方应用凭证

获取第三方应用凭证 suite_access_token

  1. OpenCpAccessTokenApi.getAccessToken(AccessTokenType.SUITE_TOKEN)

说明

获取第三方应用凭证之前需要先获取 suite_ticket,获取 suite_ticket有两种方式

获取授权企业凭证

  1. OpenCorpAccessTokenApi.getAccessToken(authCorpid, permanentCode)

说明

  • authCorpid、permanentCode 需要通过 OpenCpApi.getPermanentCode(authCode) 来获取
  • authCode 为安装应用返回的临时授权码。在 HandMsgAdapter 的 processInAuthEvent 中有回调

开源推荐