在微信小程序中接入 Cloudbase 用户认证
一句话定义:用
@cloudbase/js-sdk@2.27.3+@cloudbase/adapter-wx_mp@1.3.1,让微信小程序通过云函数签发的 ticket 登录到一个独立的 Cloudbase 环境,登录成功后前端可以直接访问该环境的数据库、云存储和云函数。预计耗时:25 分钟 | 难度:进阶
适用场景
这篇覆盖的场景是:你已经有一个独立的 Cloudbase 环境(在 tcb.cloud.tencent.com/dev 能看到那个 env-id),想让一个微信小程序作为前端接入它。
- 适用:独立 Cloudbase 环境 + 微信小程序前端
- 不适用:用的是微信开发者工具里的「云开发」(
wx.cloud)。那个属于微信·云开发,是另一套体系,直接看 微信官方文档 就行,不需要这篇 - 不适用:Web、UniApp、Taro 等,各有对应的 recipe
两套体系同名但不是一回事,一开始很容易搞混,所以特地写在最前面。
环境要求
| 依赖 | 版本 |
|---|---|
| Node.js(本地开发 + 云函数运行时) | ≥ 16.13 |
@cloudbase/js-sdk | 2.27.3 |
@cloudbase/adapter-wx_mp | 1.3.1 |
@cloudbase/node-sdk | 3.18.1 |
@cloudbase/cli | latest(用来部署云函数) |
| 微信开发者工具 | ≥ 1.06.x(需要支持「构建 npm」) |
另外需要:
- 一个已开通的 Cloudbase 环境 ID
- 微信开放平台或公众平台的小程序 AppID + AppSecret
- 在 Cloudbase 控制台「身份认证 → 登录方式」里启用「自定义登录」,并下载私钥文件
tcb_custom_login.json
第一步:安装依赖
小程序前端——进入包含 app.js 的目录(通常叫 miniprogram/):
cd miniprogram
npm init -y
npm install --save @cloudbase/js-sdk@2.27.3 @cloudbase/adapter-wx_mp@1.3.1
装完之后在微信开发者工具里点击 工具 → 构建 npm。这一步必做,不然小程序运行时找不到包,会直接报 require is not defined。
云函数目录另起:
mkdir -p cloudfunctions/getLoginTicket
cd cloudfunctions/getLoginTicket
npm init -y
npm install --save @cloudbase/node-sdk@3.18.1
把从控制台下载的 tcb_custom_login.json 放进 cloudfunctions/getLoginTicket/ 目录。这个文件带有管理员级别的签名私钥,不要提交到公开仓库,.gitignore 里加一行。
第二步:写云函数,用 wx.login 的 code 签发 ticket
cloudfunctions/getLoginTicket/index.js:
const cloudbase = require('@cloudbase/node-sdk');
const https = require('https');
const WX_APPID = process.env.WX_APPID;
const WX_SECRET = process.env.WX_SECRET;
const TCB_ENV = process.env.TCB_ENV;
const app = cloudbase.init({
env: TCB_ENV,
credentials: require('./tcb_custom_login.json'),
});
exports.main = async (event, context) => {
const { code } = event;
if (!code) {
return { error: 'MISSING_CODE', message: 'event.code is required' };
}
let session;
try {
session = await jscode2session(code);
} catch (e) {
return { error: 'WX_API_UNREACHABLE', message: e.message };
}
if (session.errcode) {
return {
error: 'WX_API_ERROR',
errcode: session.errcode,
message: session.errmsg,
};
}
const { openid, unionid } = session;
const ticket = app.auth().createTicket(openid, {
refresh: 3600 * 1000, // access_token 刷新间隔 1 小时(毫秒)
});
return { ticket, openid, unionid };
};
function jscode2session(code) {
return new Promise((resolve, reject) => {
const url =
`https://api.weixin.qq.com/sns/jscode2session` +
`?appid=${WX_APPID}` +
`&secret=${WX_SECRET}` +
`&js_code=${code}` +
`&grant_type=authorization_code`;
https
.get(url, (res) => {
let raw = '';
res.on('data', (chunk) => (raw += chunk));
res.on('end', () => {
try {
resolve(JSON.parse(raw));
} catch (err) {
reject(err);
}
});
})
.on('error', reject);
});
}
两个容易忽略的点:
WX_APPID和WX_SECRET一定要通过云函数环境变量注入。AppSecret 一旦进了仓库,重置流程比配环境变量麻烦得多,不要图省事硬编码。createTicket的第一个参数作为customUserId,微信 openid 通常是 28 位字母+数字,满足「4-32 位、字母/数字/部分符号」的规则,可以直接传。
第三步:部署云函数,开启 HTTP 访问
用 Cloudbase CLI 部署:
tcb login
tcb fn deploy getLoginTicket --dir ./cloudfunctions/getLoginTicket -e your-env-id
部署完到控制台完成三件事:
- 云函数 → getLoginTicket → 触发方式,添加「HTTP 访问服务」触发,允许
POST。复制生成的访问 URL,形如https://your-env.service.tcloudbase.com/getLoginTicket - 云函数 → getLoginTicket → 环境变量,添加
WX_APPID、WX_SECRET、TCB_ENV - 身份认证 → 登录方式,确认「自定义登录」是「已启用」状态,并且确认当前下载的
tcb_custom_login.json是最近一次生成的(每次重新生成会让旧私钥在 2 小时后 失效,这个坑后面会再提一次)
第四步:小程序端初始化 SDK,完成登录
miniprogram/libs/cloudbase.js:
import cloudbase from '@cloudbase/js-sdk';
import adapter from '@cloudbase/adapter-wx_mp';
// adapter 必须在 init 之前注册
cloudbase.useAdapters(adapter);
const app = cloudbase.init({
env: 'your-env-id',
});
export const auth = app.auth();
export default app;
miniprogram/libs/login.js:
import { auth } from './cloudbase';
const TICKET_URL = 'https://your-env.service.tcloudbase.com/getLoginTicket';
export async function ensureLogin() {
if (auth.hasLoginState()) {
return auth.currentUser;
}
// 1. wx.login 拿 code
const { code } = await new Promise((resolve, reject) => {
wx.login({ success: resolve, fail: reject });
});
// 2. 调云函数的 HTTP 接口换 ticket
const ticket = await new Promise((resolve, reject) => {
wx.request({
url: TICKET_URL,
method: 'POST',
data: { code },
success: (res) => {
if (res.statusCode === 200 && res.data && res.data.ticket) {
resolve(res.data.ticket);
} else {
reject(new Error('获取 ticket 失败: ' + JSON.stringify(res.data)));
}
},
fail: reject,
});
});
// 3. 注入 ticket 并登录
await auth.setCustomSignFunc(() => Promise.resolve(ticket));
await auth.signInWithCustomTicket();
return auth.currentUser;
}
在 miniprogram/app.js 的 onLaunch 里调用:
import { ensureLogin } from './libs/login';
App({
async onLaunch() {
try {
const user = await ensureLogin();
console.log('[cloudbase] logged in as', user.uid);
this.globalData.user = user;
} catch (err) {
console.error('[cloudbase] login failed', err);
}
},
globalData: {
user: null,
},
});
运行验证
- 微信开发者工具 → 工具 → 构建 npm
- 点击右上角 编译,打开 Console 面板
- 预期输出:
[cloudbase] logged in as 138f4c8c-xxxx-xxxx-xxxx-xxxxxxxxxxxx
uid 是 Cloudbase 侧分配的全局唯一 ID,和 openid 不是一回事——openid 是微信侧的用户标识,uid 是 Cloudbase 账号的主键,后面数据库和云存储的 owner 字段用的都是 uid。
- 去 Cloudbase 控制台 → 身份认证 → 用户管理,应该能看到一条新记录,
customUserId字段等于这次的 openid。
常见错误
| 错误码 / 错误信息 | 原因 | 修复 |
|---|---|---|
40029 | wx.login 返回的 code 已被使用或已过期(code 只能换一次 session,有效期 5 分钟) | 每次登录都重新调 wx.login,不要缓存旧 code |
45011 | jscode2session 调用太频繁(同 IP 达到上限) | 云函数里给 ticket 加一层缓存,key 用 openid,TTL 设成 5-10 分钟 |
INVALID_TICKET | 小程序端 signInWithCustomTicket 报错 | 多半是 tcb_custom_login.json 不是最新那份。控制台每次重新生成私钥,旧私钥会在 2 小时后失效,重新下载并重新部署云函数即可 |
customUserId 格式错误 | createTicket 传入了空字符串或非法字符 | 检查 jscode2session 返回值里 openid 字段是否存在,不存在说明前面已经有 errcode 了 |
require is not defined(小程序端) | 没执行「构建 npm」 | 微信开发者工具 → 工具 → 构建 npm,然后重新编译 |
错误码定义参考 docs.cloudbase.net/error-code,微信侧错误码看 微信开放文档 / 错误码。
相关文档
- SDK 初始化 —
@cloudbase/js-sdk@2.x初始化 - 自定义登录 — 登录流程的完整原理
- 微信小程序适配器 —
@cloudbase/adapter-wx_mp - Node SDK / auth.createTicket — 服务端签发 ticket
- 云函数 HTTP 访问服务 — 把云函数暴露成 HTTP 接口
@next (v3) 版本的变更点
如果你想用 @cloudbase/js-sdk@3.3.2(挂在 npm @next tag 上),和上面的代码对比有两个差异:
- 小程序适配器已内置进主包,不再需要单独安装和
cloudbase.useAdapters(adapter)这一步 - 其余代码(
cloudbase.init、auth.signInWithCustomTicket等)保持一致
v3 目前还没从 @next 提升到 latest,稳定性不如 2.27.3,生产项目建议先稳 2.x,观察一段时间再迁。
下一步
- 登录后读写云数据库:
add-database-wechat-miniprogram(待补) - 登录相关错误排查:
fix-auth-wechat-miniprogram - 从 Firebase Auth 迁过来:
migrate-firebase-auth