如何在 Firebase Authentication 中设置自定义声明
自定义声明(custom claims)是附加在 Firebase 用户上的值,例如 admin: true,它们会随用户的 ID 令牌一起传递。大多数应用正是用它们给用户赋予角色,供安全规则和后端检查。Firebase 控制台无法设置自定义声明,甚至不会显示它们:Authentication > 用户(Users)中没有任何声明字段。声明要通过 Admin SDK 设置,有三种方法可以做到,哪一种合适,取决于由谁分配角色、多久分配一次。
更新于 2026年10月27日。 方法 1 中的扩展程序 Firexport 是我们开发的。方法 2 和 3 不需要它。
简短回答
| 1. 控制台 + 扩展程序 | 2. Admin SDK 脚本 | 3. Cloud Function | |
|---|---|---|---|
| 准备工作 | 安装一个 Chrome 扩展程序,连接你的 Google 账号 | Node.js 和 Google Cloud 凭据 | 一个已部署的函数,以及应用中的代码 |
| 由谁设置声明 | 你(在控制台中) | 你(在终端中) | 应用的管理员 |
| 已有的声明 | 显示出来,除非你删除,否则保留 | 保留,并合并新的声明 | 保留,并合并新的声明 |
| 需要启用结算 | 不需要 | 不需要 | 需要(Blaze 方案) |
1. 用 Firexport 在 Firebase 控制台中设置声明
Firexport 是一款免费的 Chrome 扩展程序,会在 Authentication > 用户(Users)中每个用户的 ⋮ 菜单里添加编辑用户。它的窗口把用户的自定义声明逐行列出,你可以添加、修改和删除这些行,旁边还有该用户的电子邮件、密码、个人资料和登录提供方。它使用你连接的 Google 账号保存,因此无需设置服务账号密钥,也无需编写代码。
- 从 Chrome 应用商店安装 Firexport。
- 在 Firebase 控制台中,打开 Authentication > 用户(Users)。
- 把鼠标悬停在该用户所在的行上,点击行最右侧的 ⋮,然后选择编辑用户。
- 第一次使用时,窗口会要求你连接 Google 账号:选择在控制台中登录的账号,并在 Google 的窗口中允许它管理 Firebase Authentication 用户。
- 在自定义声明下,点击添加声明,输入声明的名称,例如
admin,然后选择类型:string、number、boolean、object、array 或 null。object 和 array 内部还可以包含更多行。 - 点击保存。只会保存你更改的内容,该用户的其他声明保持不变。
窗口会检查什么
- 大小。Firebase 每个用户最多接受 1,000 字节的声明。窗口会在你输入时统计字节数,超出上限就不会保存。
- 保留名称。顶层声明不能使用 Firebase 保留给自己令牌字段的名称,例如
sub、aud、exp或firebase。窗口会在你保存之前标出这样的名称。 - 他人所做的更改。如果在你打开窗口之后该用户被更改过,就不会保存任何内容,你可以读取最新的值后重试。
如果只想查看用户的声明而不做任何更改,点击行操作最前面的信息图标:它的卡片会列出该用户的完整记录,包括自定义声明。要给尚不存在的用户分配角色,添加用户按钮的 ⋮ 菜单中有高级,可以连同其他字段一起填写声明。保存时使用所连接账号的权限,该账号需要拥有管理 Firebase Authentication 用户的权限。你的用户数据从浏览器直接发送到 Google,从不发送给我们。编辑用户功能在所有方案中都免费。

不用脚本、不用服务账号密钥,直接在控制台中设置和查看 Firebase 自定义声明。
2. 用 Admin SDK 脚本设置声明
如果要给许多用户设置同一个声明,或者想把它写进一个可以再次运行的脚本,请在 Node.js 中使用 Firebase Admin SDK。下面的脚本接收 JSON 格式的声明和任意数量的 UID 或电子邮件,并把这些声明合并到每个用户已有的声明中。它需要一个能管理用户的账号:项目 Owner 或 Editor,或者 Firebase Authentication Admin 角色。
- 安装 SDK:
npm install firebase-admin - 登录以获取本地凭据:
gcloud auth application-default login。在服务器上,改为让GOOGLE_APPLICATION_CREDENTIALS指向服务账号密钥。 - 把下面的脚本保存为
set-claims.mjs,替换your-project-id,然后运行node set-claims.mjs '{"admin":true}' maya@example.com。
// Usage: node set-claims.mjs '{"admin":true}' maya@example.com u2 → adds admin: true to each user's claims
// Users are UIDs or emails. The claims you pass are merged into the ones each user has; null removes one.
import { initializeApp } from 'firebase-admin/app';
import { getAuth } from 'firebase-admin/auth';
initializeApp({ projectId: 'your-project-id' });
const auth = getAuth();
const [json, ...users] = process.argv.slice(2);
if (!json || !users.length) throw new Error(`Usage: node set-claims.mjs '{"admin":true}' <uid or email> ...`);
const changes = JSON.parse(json);
if (typeof changes !== 'object' || changes === null || Array.isArray(changes)) throw new Error('Pass the claims as a JSON object');
for (const who of users) {
const user = who.includes('@') ? await auth.getUserByEmail(who) : await auth.getUser(who);
// setCustomUserClaims() replaces every claim the user has, so start from the current ones.
const claims = { ...user.customClaims, ...changes };
for (const [name, value] of Object.entries(claims)) if (value === null) delete claims[name];
await auth.setCustomUserClaims(user.uid, claims);
console.log(`${who}: ${JSON.stringify(claims)}`);
}setCustomUserClaims()会用你传入的内容替换用户的全部声明。这就是脚本先读取当前声明的原因:如果只传入{"admin":true}来调用它,其他声明都会被删除。- 值为
null会删除对应的声明,所以{"admin":null}会收回这个角色。 - 声明超过 1,000 字节或使用了保留名称时,Admin SDK 会抛出错误,该用户会保留原有的声明。
3. 用 Cloud Function 让应用的管理员设置声明
如果角色是应用本身的一部分,例如在管理界面中任命版主,Admin SDK 就必须运行在你控制的服务器上。通常把它放在可调用的 Cloud Function 中。下面的函数允许令牌中已有 admin: true 的用户为其他用户设置声明。部署函数需要 Blaze 方案。
// functions/index.js: a callable function your app's admin screen calls as setClaims({ uid, claims })
const { onCall, HttpsError } = require('firebase-functions/v2/https');
const { initializeApp } = require('firebase-admin/app');
const { getAuth } = require('firebase-admin/auth');
initializeApp();
exports.setClaims = onCall(async (request) => {
// Only a user whose token already says admin: true may change claims. Give the first admin theirs another way.
if (request.auth?.token.admin !== true) throw new HttpsError('permission-denied', 'Only admins can set claims');
const { uid, claims } = request.data;
const user = await getAuth().getUser(uid);
const next = { ...user.customClaims, ...claims }; // setCustomUserClaims() replaces them all, so keep the others
await getAuth().setCustomUserClaims(uid, next);
return { uid, claims: next };
});用 firebase deploy --only functions 部署它,然后在应用中调用:
import { getFunctions, httpsCallable } from 'firebase/functions';
await httpsCallable(getFunctions(), 'setClaims')({ uid: 'u1', claims: { editor: true } });总得有人成为第一个管理员。请用方法 1 或 2 给这个账号设置 admin 声明。
新声明何时生效,以及如何使用
声明存放在 ID 令牌中,Firebase 大约每小时刷新一次这个令牌。用户会在下一次刷新或下一次登录时拿到新的声明。要立即拿到,应用可以对已登录的用户调用 getIdToken(true),再用 getIdTokenResult() 读取声明。安全规则从 request.auth.token 中读取声明:
match /posts/{postId} {
allow read: if true;
allow write: if request.auth != null && request.auth.token.admin == true;
}- 声明用于控制访问权限,而不是存放个人资料。它们会随每个请求一起发送,而且 Firebase 把上限定为 1,000 字节。
- 用户解码自己的令牌就能读到自己的声明,所以不要在其中存放机密信息。
- 要把所有用户的声明汇总到一个文件中,请导出用户。Firebase Auth 用户导出指南介绍了三种方法。
常见问题
Firebase 控制台能设置自定义声明吗?
仅靠控制台不行。Authentication > 用户(Users)中没有自定义声明字段,也不会显示它们。自定义声明要通过 Admin SDK 设置(在脚本、服务器或 Cloud Function 中),或者使用 Firexport 这样的浏览器扩展程序,它会在用户(Users)标签页上添加“编辑用户”。
如何查看用户的自定义声明?
控制台不显示它们。使用 Admin SDK 时,getUser(uid) 会在 customClaims 中返回它们。在应用中,getIdTokenResult() 会在 claims 中返回已登录用户的声明。Firexport 会在 Authentication > 用户(Users)中每一行的信息卡片上显示它们。
为什么我的应用看不到新的自定义声明?
声明是从 ID 令牌中读取的,而用户当前的令牌是在你设置声明之前签发的。Firebase 会在一小时内刷新令牌,重新登录也会获得新的令牌。要立即拿到新声明,请对已登录的用户调用 getIdToken(true)。
setCustomUserClaims 会替换已有的声明吗?
会。它会把用户的声明完全设为你传入的对象,所以对象中没有的声明都会被删除。请先用 getUser() 读取当前的声明,再把你的更改合并进去,就像上面的脚本那样。传入 null 会删除全部声明。
Firebase 自定义声明最大可以有多大?
一个用户的全部声明合计最多 1,000 字节(按 JSON 计算)。Firebase 自己的令牌字段所用的顶层名称是保留的:acr、amr、at_hash、aud、auth_time、azp、cnf、c_hash、exp、firebase、iat、iss、jti、nbf、nonce 和 sub。
