微信凭证管理终极方案!UniCloud uni-open-bridge-common实战避坑指南一

336 阅读6分钟

本文分二个部分,第一个部分先介绍微信开发中,access_tokenjsapi_ticket是最关键的凭证。

相信许多开发者习惯自己实现这些凭证的获取和管理,扫码需要,然后自动 login 需要。 但在UniCloud环境下,我更推荐的一种方式是使用 uni-open-bridge-common 模块来实现相关的功能。 它提供了更加统一和可靠的解决方案。本文详细介绍这两种凭证的管理方式及最佳实践。

微信凭证介绍

access_token

access_token是调用微信接口的全局唯一凭证,由appidsecret获取,有效期通常为7200秒(2小时)。它用于调用各种微信API,如获取用户信息、发送模板消息等。 关于微信的access_token,有几个重要特性需要理解:

access_token的全局唯一性

  1. 全局唯一性:对于同一个微信应用(同一个AppID),access_token是全局唯一的

  2. 互相覆盖问题:当有人获取了新的access_token,之前的token会立即失效

    • 这在微信官方文档中明确说明:"重复获取将导致上次获取的access_token失效"

    • 所以如果多个系统都使用相同的AppID各自获取token,会导致相互间的token失效

  3. 实际影响:

    • 系统A获取token → 可以正常使用

    • 系统B也获取token → 系统A的token立即失效

    • 系统A使用失效token调用接口 → 报错"invalid credential"

jsapi_ticket

jsapi_ticket是用于微信JS-SDK的临时票据,通过access_token获取,同样有效期为7200秒。它用于生成JS-SDK权限验证的签名,用于网页中调用微信JS-SDK的各种功能。

传统实现方式及问题

传统实现示例

// 获取access_token
async function getAccessToken() {
  const url = `https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${appid}&secret=${secret}`;
  const res = await fetch(url);
  const data = await res.json();
  
  // 存储到缓存
  await redis.set('wx_access_token', data.access_token, 'EX', 7000);
  return data.access_token;
}

// 获取jsapi_ticket
async function getJsapiTicket() {
  const token = await getAccessToken();
  const url = `https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=${token}&type=jsapi`;
  const res = await fetch(url);
  const data = await res.json();
  
  // 存储到缓存
  await redis.set('wx_jsapi_ticket', data.ticket, 'EX', 7000);
  return data.ticket;
}

存在的问题

  1. 各应用独立实现:不同云函数可能各自实现获取凭证的逻辑
  2. 凭证冲突:相同appid的凭证被多个系统独立获取,导致之前获取的失效
  3. 请求频率限制:微信对获取凭证有频率限制,容易触发限制
  4. 存储不统一:缓存键命名不一致,难以管理
  5. 缺乏更新机制:没有考虑凭证提前失效的情况

uni-open-bridge-common解决方案

模块优势

  1. 统一管理:集中管理所有微信凭证
  2. 分类存储:根据不同平台(小程序、公众号等)和appid分别存储
  3. 多层缓存:同时使用数据库和Redis缓存,保证可靠性
  4. 自动刷新:内置更新机制,处理凭证失效
  5. 跨云函数共享:所有云函数可共享同一套凭证

使用的URL

  1. access_token获取URL

    • 稳定版接口:https://api.weixin.qq.com/cgi-bin/stable_token(POST请求)
    • 传统接口:https://api.weixin.qq.com/cgi-bin/token(GET请求,已不推荐)
  2. jsapi_ticket获取URL

    • https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi(POST请求)

1. 获取access_token

const { getAccessToken } = require("uni-open-bridge-common");

async function getWXAccessToken() {
  try {
    const result = await getAccessToken({
      dcloudAppid: "__UNI__77XXXX",  // 应用的DCloud AppID
      provider: "weixin-h5",          // 平台类型:weixin-mp(小程序)、weixin-h5(公众号)等
      appid: "wx1234567890",          // 微信AppID
      secret: "abcdefg1234567890"     // 微信AppSecret
    });
    
    return result.access_token;
  } catch (error) {
    console.error("获取access_token失败:", error);
    throw error;
  }
}

2. 获取jsapi_ticket

const { getTicket } = require("uni-open-bridge-common");

async function getWXTicket() {
  try {
    const result = await getTicket({
      dcloudAppid: "__UNI__77XXXX",  // 应用的DCloud AppID
      provider: "weixin-h5",          // 平台类型:weixin-mp(小程序)、weixin-h5(公众号)等
    });
    
    return result.ticket;
  } catch (error) {
    console.error("获取jsapi_ticket失败:", error);
    throw error;
  }
}

大家有没有注意到,上面其实不用先取 access_token, 理论上自己实现(见上文),是需要传 AccessToken 才可以取得到 获取jsapi_ticket. 这说一下 uni-open-bridge-common 是通过什么机制获取这些信息的:

  1. 配置中心读取:模块会从uni-config-center的uni-id配置中读取凭证信息
       // uni-open-bridge-common内部的AppConfig类
       getAppConfig(appid) {
         // 从uni-id配置中读取
         const uniIdConfig = configCenter({ pluginId'uni-id' }).config()
         // ...
       }
  1. 需要正确配置:您必须确保在commone/uni-config-center/uni-id/config.json中已配置了微信应用信息:

     {
       "web": {
         "oauth": {
           "weixin-h5": {
             "appid": "wx123456789",
             "appsecret": "abcdef123456789"
           }
         }
       }
     }
  1. 查找逻辑:当您传入dcloudAppid和provider时,系统会:
  • 根据dcloudAppid找到对应的uni-id配置
  • 根据provider找到相应的微信应用配置
  • 从配置中获取appid和secret

3. 强制刷新token

const { updateAccessToken } = require("uni-open-bridge-common");

async function refreshToken() {
  try {
    await updateAccessToken({
      dcloudAppid: "__UNI__7741880",
      provider: "weixin-h5"
    });
    console.log("access_token已强制刷新");
  } catch (error) {
    console.error("刷新access_token失败:", error);
    throw error;
  }
}

验证存储是否成功

在Redis中查询

Redis存储格式

  1. 连接到UniCloud 后台 Redis(通过控制台或Redis客户端)

  2. 查询access_token:

    键名:uni-id:<provider>:<appid>:access-token

    KEYS uni-id:weixin-h5:*:access-token
    

    后台可以直接输入 :access-token。全局只有一条。根据 provider 和 appid 来确认全局。

  3. 查询ticket:

    键名:uni-id:<provider>:<appid>:ticket

    KEYS uni-id:weixin-h5:*:ticket
    

    后台可以直接输入:ticket查看,会有很多。每个用户一条。

  4. 获取具体值:

    GET uni-id:weixin-h5:wxaefc501c799f7d92:access-token
    

在数据库中查询

  1. 打开opendb-open-data集合
  2. 查询条件:_id 包含 access-tokenticket
  3. 值应该包含有效的JSON数据,包括过期时间

多应用场景下的最佳实践

情况1:相同云空间不同应用使用不同AppID

这是理想情况,每个应用使用独立的微信凭证。uni-open-bridge-common通过dcloudAppid和provider区分,不会产生冲突。

情况2:相同云空间不同应用使用相同AppID

此情况下会共享凭证,需要确保:

  1. 所有应用使用uni-open-bridge-common获取凭证
  2. 不要在不同应用中使用自定义实现获取凭证
  3. 如有特殊需求,可考虑不同应用使用不同的provider类型

情况3:支付场景

支付相关功能也需要access_token,建议:

  1. 修改支付模块使用uni-open-bridge-common获取凭证
  2. 确保支付用的provider(如weixin-mp)与公众号(weixin-h5)不同
  3. 如果必须使用相同provider,则确保所有云函数都使用统一的获取方式

注意事项和常见问题

  1. 凭证失效问题:如遇到"invalid credential"错误,可以尝试:

    • 使用updateAccessToken强制刷新
    • 确认appid和secret配置正确
    • 检查微信公众平台IP白名单配置
  2. 多环境部署:dev/test/prod环境应使用不同的appid,避免相互影响

  3. 不建议混用:不要在同一应用中混用uni-open-bridge-common和自定义实现

  4. 注意平台类型weixin-mp(小程序)、weixin-h5(公众号)、weixin-web(H5应用)在内部处理上有差异

总结

uni-open-bridge-common模块为UniCloud环境下的微信凭证管理提供了统一、可靠的解决方案。通过标准化的键名格式、多层缓存策略和自动刷新机制,大大简化了开发者的工作,提高了微信凭证管理的效率和可靠性。

在新项目中,强烈建议使用uni-open-bridge-common替代自定义实现;在现有项目中,建议逐步迁移到该模块,确保凭证管理的稳定性和一致性。