Skip to content

微信小程序登录鉴权实践

小程序没有传统 Web 的 Cookie/Session 环境,登录态需要自己设计。本文介绍我们在商城类小程序中稳定运行的登录鉴权方案。

登录流程

整体流程如下:

  1. 小程序端调用 wx.login() 获取临时登录凭证 code
  2. code 提交给后端 /api/v1/auth/login
  3. 后端调用微信 code2Session 接口,用 appid + secret + code 换取 openidsession_key
  4. 后端根据 openid 查找或创建用户,签发自定义登录态 token 返回
  5. 小程序端将 token 存入本地缓存,后续请求携带
text
小程序                    后端                      微信服务器
  │ wx.login() 得 code      │                          │
  │ ─── POST /login ──────> │ ─── code2Session ──────> │
  │                         │ <── openid/session_key ── │
  │                         │ 查找/创建用户、签发 token   │
  │ <── token ───────────── │                          │
  │ setStorageSync(token)   │                          │

为什么不用 openid 直接当登录态

  • openid 是固定值,一旦泄露可被永久伪造请求
  • 无法主动失效、无法控制有效期

正确做法是后端签发不透明的随机 token(如 UUID + 用户信息的缓存映射)或 JWT,并设置有效期(建议 7 天以内)。

请求携带与响应拦截

小程序端封装统一的请求模块:

js
// utils/request.js 核心逻辑
function request(options) {
  const token = wx.getStorageSync('token')
  return new Promise((resolve, reject) => {
    wx.request({
      ...options,
      header: { Authorization: `Bearer ${token}`, ...options.header },
      success(res) {
        if (res.data.code === 0) return resolve(res.data.data)
        // 登录态失效:静默重新登录后重试一次
        if (res.statusCode === 401) return reloginAndRetry(options)
        wx.showToast({ title: res.data.message, icon: 'none' })
        reject(res.data)
      },
      fail: reject
    })
  })
}

关键点:收到 401 时静默重新走一遍登录流程并重试原请求,用户无感知。

安全要点

  • session_key 绝不能下发给前端,它用于解密手机号等敏感数据,只能保存在服务端
  • code 是一次性的,不可重复使用,不可由前端直接调用 code2Session(会暴露 secret)
  • 所有需鉴权接口服务端必须校验 token,不要信任客户端传来的用户 ID
  • 手机号等敏感信息解密应放在后端完成,前端只展示结果

常见问题

  • token 存哪儿wx.setStorageSync 即可,不要放全局变量(小程序可能被杀掉重启)
  • 多端登录:如需"互踢",后端保存用户与 token 的映射关系,新登录时使旧 token 失效
  • token 过期时间:太短会导致频繁重登,太长风险高;配合静默续期可以用较短的 7 天

小结

方案核心是「codeopenid、后端签发自己的 token、401 静默重登」。这套流程我们已在多个商城类小程序中落地,稳定运行多年。