PAYATHON 2026

为什么邮箱验证后 Firestore 规则仍返回 permission-denied?

数据小陈

结论

最可能的原因是,邮箱验证后客户端的 User 状态已更新,但 Firestore 请求仍使用旧的 Firebase ID token。安全规则读取的是 token 中的 request.auth.token.email_verified,所以仅调用 reload(),规则未必能立即读取到更新后的声明。应用重启并重新登录后会获取新 token,因此请求能够成功。

刷新用户状态和 ID token

邮箱验证完成后,先重新加载用户状态,再从 FirebaseAuth.instance.currentUser 获取当前用户,并强制刷新 ID token。确认 emailVerified 为 true 后,再调用 loadPlayer():

final auth = FirebaseAuth.instance;

await auth.currentUser?.reload();
final user = auth.currentUser;

if (user?.emailVerified == true) {
  await user!.getIdToken(true); // 强制刷新 ID token,使新声明用于后续请求
  await loadPlayer();
}

不必手动将 getIdToken(true) 返回的 token 传给 Firestore。刷新 Firebase Auth 的 token 后,后续 Firestore 请求会使用更新后的认证状态。loadPlayer() 中也可以保留对 emailVerified 的检查。

检查规则与调用路径

规则要求请求通过认证、token 中的 email_verified 声明为真,并且文档路径中的用户 ID 与 request.auth.uid 一致:

allow read, write: if isSignedIn() && request.auth.uid == userId;

如果刷新 token 后仍收到 permission-denied,可以依次检查:

  • FirebaseAuth.instance.currentUser?.emailVerified 在 reload() 后是否确实为 true。
  • 读取路径是否为 /users/{当前用户 uid},并与已部署的规则匹配。
  • 调用使用的 Firebase 项目是否与部署规则的项目一致。
  • 规则是否已部署,以及是否有其他规则或请求状态影响访问。

还要确认 token 刷新发生在 get() 或 set() 之前。如果只在 reload() 前检查旧的用户对象,或在刷新 token 前立即发出 Firestore 请求,该请求可能仍会使用旧的验证声明。

备注:内容仅供参考。