You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决Firebase RTDB认证后立即读取权限被拒问题?

解决Firebase认证后立即读取数据库权限拒绝问题

问题现象

Web端完成Firebase邮箱密码认证后,立即读取数据库会触发权限拒绝错误,但重新加载页面后再登录,就能正常读取数据。

错误信息

Error: permission_denied at /sandboxusers/KEY_USER_ID/companies:
Client doesn't have permission to access the desired data.

当前安全规则

"sandboxusers" : {
  "$user_id" : {
    ".read": "auth != null",
    ".write": false
  }
},

已尝试的临时方案

  • 将.read设为true:代码可正常运行,但数据库完全暴露给任意用户,存在严重安全隐患
  • 认证流程后添加500ms延迟:能临时绕过问题,但方案不可靠且不符合开发规范

现有认证代码

页面调用认证的代码

Map info = await userProvider.signIn(user.user!, user.password!);

if (info['ok']) {
  await Future.delayed(const Duration(milliseconds: 500), () {}); // 需要移除的延迟
  Navigator.of(context).pushNamedAndRemoveUntil('parameters', (route) => false); // 跳转到读取数据库的参数页面
} else {
  // 认证失败提示信息
}

UserProvider中的signIn方法

Future <Map<String, dynamic>> signIn(String email, String password) async {
   
  try {
     UserCredential result = await FirebaseAuth.instance.signInWithEmailAndPassword(email: email, password: password);
     User user = result.user!;
     return {'ok' : true, 'localId': user.uid, 'email' : user.email};
  } on FirebaseAuthException catch (e) {
       log('$e');
     return {'ok': false, 'code': e.code, 'message': '${e.message}' };
  }
}

无效的尝试

曾尝试通过authStateChanges回调跳转,但未生效:

if (info['ok']) {
  FirebaseAuth.instance.authStateChanges().listen((User? user) {
    if (user != null) {
      Navigator.of(context).pushNamedAndRemoveUntil('parametros', (route) => false);
    }
  });
} else {
  // 认证失败提示信息
}

解决方案

原因分析

问题核心:signInWithEmailAndPassword返回成功时,Firebase Auth的本地认证状态还未完全同步到Realtime Database客户端,此时发起数据库请求,数据库端无法识别到有效认证信息,导致规则校验失败。

正确实现方式

方式1:通过idTokenChanges监听确保状态同步

idTokenChanges会在用户认证状态变更且token就绪时触发,比authStateChanges更适合确保数据库权限校验通过:

userProvider.signIn(user.user!, user.password!).then((info) {
  if (info['ok']) {
    StreamSubscription? subscription;
    subscription = FirebaseAuth.instance.idTokenChanges().listen((User? user) {
      if (user != null) {
        // 取消订阅避免多次触发跳转
        subscription?.cancel();
        Navigator.of(context).pushNamedAndRemoveUntil('parameters', (route) => false);
      }
    });
  } else {
    // 认证失败提示信息
  }
}).catchError((error) {
  // 处理异常
});

方式2:强制刷新ID Token

直接调用getIdToken(true)强制刷新token,确保认证状态完全同步后再跳转:

Map info = await userProvider.signIn(user.user!, user.password!);

if (info['ok']) {
  // 强制刷新并获取最新token,确保数据库客户端已同步认证状态
  await FirebaseAuth.instance.currentUser?.getIdToken(true);
  Navigator.of(context).pushNamedAndRemoveUntil('parameters', (route) => false);
} else {
  // 认证失败提示信息
}

安全规则优化建议

为进一步提升安全性,建议将规则限制为仅登录用户能访问自己的数据:

"sandboxusers" : {
  "$user_id" : {
    ".read": "auth != null && auth.uid == $user_id",
    ".write": false
  }
},

内容的提问来源于stack exchange,提问作者David L

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.20 08:04:56