为什么邮箱验证后 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 请求,该请求可能仍会使用旧的验证声明。
备注:内容仅供参考。
