小程序登录流程是怎样的?openid、unionid 和 session_key 有什么区别?
简化版
小程序登录通常是前端调用 wx.login 获取临时 code,发送给后端,后端用 code 换取 openid、session_key,再生成自己的登录态返回给前端。openid 标识用户在当前小程序下的身份,unionid 在满足条件时可关联同一开放平台账号下的应用,session_key 用于微信会话校验及旧版加密数据流程,不应下发给前端。
详细版
典型流程:
- 小程序调用
wx.login获取临时code。 - 前端把
code发送给业务后端。 - 后端调用微信接口,用
code换取openid和session_key。 - 后端根据
openid查找或创建用户。 - 后端生成业务 token 或 session,返回给前端。
- 前端保存业务登录态,后续请求携带它。
几个概念:
openid:用户在某个小程序下的唯一标识。unionid:满足返回条件时,用于关联同一开放平台账号下的多个应用。session_key:微信侧会话密钥,用于会话校验及旧版加密数据解密,应保存在服务端;新版手机号动态 code 流程由后端换取数据。
完整版教学
一、为什么不能只靠前端登录
wx.login 返回的 code 只是临时凭证,不是用户身份本身。它需要由后端拿着小程序的 appid 和密钥去微信服务端换取用户标识。
如果把密钥放到前端,等于暴露应用凭证,存在严重安全风险。因此登录闭环必须有服务端参与。
二、openid、unionid、session_key 的区别
openid 是用户在当前小程序内的唯一标识。不同小程序之间,即使是同一个微信用户,openid 通常也不同。
unionid 用于同一开放平台账号主体下的多个应用打通用户身份。例如公众号、小程序、App 都绑定到同一开放平台主体时,可以用 unionid 判断是不是同一个微信用户。
session_key 是微信返回给后端的会话密钥,可用于微信会话相关校验及旧版 encryptedData 流程。它不是业务 token,也不应该直接发给客户端;具体敏感能力若已改为动态 code,应由后端按新接口换取。
三、业务登录态怎么设计
后端拿到 openid 后,一般不会直接让前端每次携带 openid 请求,而是生成自己的登录态,比如 JWT 或 session token。
这样有几个好处:
- 可以加入业务用户 ID、角色、过期时间。
- 可以统一管理登录失效。
- 可以避免把微信侧细节暴露给前端。
- 可以支持多端、多渠道登录体系。
前端只需要保存业务 token,并在请求头中携带。
四、面试追问与工程落地
面试官可能问:“session_key 能不能存在前端?”
不应该。session_key 用于解密微信敏感数据,如果泄露,可能带来隐私风险。正确做法是后端保存或短期使用它:历史 encryptedData 流程由后端解密;当前手机号动态 code 流程则由后端调用对应服务端接口换取,不能混用。
工程中还要处理 code 过期、token 过期、静默登录失败、用户拒绝授权等异常。登录不是一个 API 调完就结束,而是要设计完整的状态恢复流程。
五、凭证边界与完整时序
wx.login 的 code 是短期、一次性交换凭证,前端拿到后应尽快交给自己的后端,不能把它当业务 token 缓存复用。后端通过微信的 code2Session 接口交换身份信息时需要 appid 与 AppSecret,所以该调用只能发生在可信服务端。
小程序 wx.login
│ 临时 code
▼
业务后端 ── code + AppSecret ──> 微信服务端
│ <── openid + session_key ──
│ 查/建业务用户,签发业务 session
▼
小程序只保存业务登录态
| 数据 | 谁签发/返回 | 应保存位置 | 用途 |
|---|---|---|---|
code | wx.login | 短暂存在客户端 | 仅用于服务端换取微信会话 |
openid | 微信服务端 | 业务后端 | 当前小程序内识别用户 |
unionid | 微信服务端,满足条件时 | 业务后端 | 同开放平台账号下合并身份 |
session_key | 微信服务端 | 业务后端 | 微信会话相关校验/旧流程解密 |
| 业务 token | 业务后端 | 客户端受控存储 | 访问自己的业务接口 |
例如业务 token 设计为 2 小时、刷新凭证 7 天只是一个可讨论的产品方案,不是微信平台固定值。短 token 缩小泄露窗口,刷新机制改善体验;服务端仍要支持封禁、退出和设备风险发生时主动撤销。
六、新旧敏感数据流程与账号合并
要区分历史上的 encryptedData + iv + session_key 解密流程和当前某些能力返回动态 code 的流程。以新版手机号能力为例,前端在用户主动触发后取得动态 code,后端再用服务端接口换手机号;不能把所有手机号获取都回答成“把 session_key 发给前端解密”。具体能力应以对应基础库和开放文档为准。
unionid 不是每次登录都必然返回,只有应用满足开放平台绑定等条件且处于支持场景时才可获得。业务库应以自己的 user id 为主键,建立 (appid, openid) 唯一映射;拿到 unionid 后再执行可审计的账号合并,避免把缺失 unionid 的用户误合并。
登录接口还要防止会话固定和重放:成功交换 code 后创建新业务会话,不接纳客户端指定的用户 id;绑定手机号、修改资料等操作重新校验当前业务身份。若 100 个并发请求同时发现“用户不存在”,数据库唯一约束和事务必须保证只创建一个用户记录。
安全心法:
AppSecret与session_key不出服务端,openid不是授权凭证,真正访问业务资源还要验证业务登录态和资源权限。
七、常见误区与追问
- 误区:
wx.login成功就代表用户已经登录业务系统。 它只拿到临时 code,必须由后端完成交换、用户映射和业务会话签发。 - 误区:openid 可以直接作为接口鉴权 token。 openid 只是标识符,不证明当前请求者拥有该身份,客户端提交的 openid 可被篡改。
- 误区:unionid 在所有小程序登录中都会返回。 它受开放平台绑定和具体返回条件限制,业务必须兼容缺失情况。
- 追问:session_key 为什么不能返回前端? 它属于微信会话机密,泄露会破坏相关数据校验或旧流程解密的安全边界。
- 追问:新版手机号获取还需要前端解密吗? 动态 code 流程由后端调用服务端接口换取手机号,不应套用旧版客户端传 encryptedData 的固定答案。
- 追问:code 交换失败如何处理? 不签发业务 token,区分过期、已使用、网络和配置错误,必要时重新调用
wx.login,同时记录可诊断但不含密钥的日志。 - 追问:同一用户有多个小程序 openid 怎么合并? 在满足条件时用 unionid 建立关联,再映射到统一业务 user id,并处理历史账号冲突。
八、加强记忆
登录流程按“两次换票”记:客户端用 wx.login 拿临时 code,后端用 code 换微信身份,再由后端签发自己的业务登录态。openid 管单个 appid 下的身份,unionid 在满足条件时跨同一开放平台账号关联,session_key 留在服务端;手机号等敏感能力还要区分动态 code 新流程和历史解密流程。