Firexport指南

如何在 Firebase Authentication 中设置自定义声明

自定义声明(custom claims)是附加在 Firebase 用户上的值,例如 admin: true,它们会随用户的 ID 令牌一起传递。大多数应用正是用它们给用户赋予角色,供安全规则和后端检查。Firebase 控制台无法设置自定义声明,甚至不会显示它们:Authentication > 用户(Users)中没有任何声明字段。声明要通过 Admin SDK 设置,有三种方法可以做到,哪一种合适,取决于由谁分配角色、多久分配一次。

更新于 2026年10月27日。 方法 1 中的扩展程序 Firexport 是我们开发的。方法 2 和 3 不需要它。

简短回答

  • 现在就要给一个或几个用户分配角色: 用浏览器扩展程序在用户(Users)标签页中设置。 方法 1
  • 在终端中给许多用户设置同一个声明: 一段简短的 Admin SDK 脚本。 方法 2
  • 由应用自己的管理员分配的角色: 一个可调用的 Cloud Function。 方法 3
1. 控制台 + 扩展程序2. Admin SDK 脚本3. Cloud Function
准备工作安装一个 Chrome 扩展程序,连接你的 Google 账号Node.js 和 Google Cloud 凭据一个已部署的函数,以及应用中的代码
由谁设置声明你(在控制台中)你(在终端中)应用的管理员
已有的声明显示出来,除非你删除,否则保留保留,并合并新的声明保留,并合并新的声明
需要启用结算不需要不需要需要(Blaze 方案)

1. 用 Firexport 在 Firebase 控制台中设置声明

Firexport 是一款免费的 Chrome 扩展程序,会在 Authentication > 用户(Users)中每个用户的 ⋮ 菜单里添加编辑用户。它的窗口把用户的自定义声明逐行列出,你可以添加、修改和删除这些行,旁边还有该用户的电子邮件、密码、个人资料和登录提供方。它使用你连接的 Google 账号保存,因此无需设置服务账号密钥,也无需编写代码。

  1. 从 Chrome 应用商店安装 Firexport。
  2. 在 Firebase 控制台中,打开 Authentication > 用户(Users)。
  3. 把鼠标悬停在该用户所在的行上,点击行最右侧的 ⋮,然后选择编辑用户。
  4. 第一次使用时,窗口会要求你连接 Google 账号:选择在控制台中登录的账号,并在 Google 的窗口中允许它管理 Firebase Authentication 用户。
  5. 在自定义声明下,点击添加声明,输入声明的名称,例如 admin,然后选择类型:string、number、boolean、object、array 或 null。object 和 array 内部还可以包含更多行。
  6. 点击保存。只会保存你更改的内容,该用户的其他声明保持不变。

窗口会检查什么

  • 大小。Firebase 每个用户最多接受 1,000 字节的声明。窗口会在你输入时统计字节数,超出上限就不会保存。
  • 保留名称。顶层声明不能使用 Firebase 保留给自己令牌字段的名称,例如 sub、aud、exp 或 firebase。窗口会在你保存之前标出这样的名称。
  • 他人所做的更改。如果在你打开窗口之后该用户被更改过,就不会保存任何内容,你可以读取最新的值后重试。

如果只想查看用户的声明而不做任何更改,点击行操作最前面的信息图标:它的卡片会列出该用户的完整记录,包括自定义声明。要给尚不存在的用户分配角色,添加用户按钮的 ⋮ 菜单中有高级,可以连同其他字段一起填写声明。保存时使用所连接账号的权限,该账号需要拥有管理 Firebase Authentication 用户的权限。你的用户数据从浏览器直接发送到 Google,从不发送给我们。编辑用户功能在所有方案中都免费。

Firexport 在 Authentication > 用户标签页中添加的用户详情卡片,靠近底部是该用户的自定义声明:role 为 admin,team 为 support
信息图标打开的卡片会显示控制台不显示的声明,这里是一个角色和一个团队。

不用脚本、不用服务账号密钥,直接在控制台中设置和查看 Firebase 自定义声明。

添加到 Chrome — 免费

2. 用 Admin SDK 脚本设置声明

如果要给许多用户设置同一个声明,或者想把它写进一个可以再次运行的脚本,请在 Node.js 中使用 Firebase Admin SDK。下面的脚本接收 JSON 格式的声明和任意数量的 UID 或电子邮件,并把这些声明合并到每个用户已有的声明中。它需要一个能管理用户的账号:项目 Owner 或 Editor,或者 Firebase Authentication Admin 角色。

  1. 安装 SDK:npm install firebase-admin
  2. 登录以获取本地凭据:gcloud auth application-default login。在服务器上,改为让 GOOGLE_APPLICATION_CREDENTIALS 指向服务账号密钥。
  3. 把下面的脚本保存为 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。