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

Firebase实时数据库规则配置问题:UID验证后无法读写指定节点

Firebase实时数据库规则修正方案

问题背景

我在Firebase实时数据库中有activeDrivers和ALL Ride Requests两个节点,需要让已验证的用户或司机对这两个节点执行读写操作,但当前规则配置未生效。

  • activeDrivers节点的ID与发起操作的司机UID一致
  • ALL Ride Requests节点的ID是动态生成的随机值

当前数据库规则

{
  "rules": {
    "drivers": {
      "$uid": {
        ".read": "auth !== null && auth.uid === $uid",
        ".write": "auth !== null && auth.uid === $uid",
      }

    },
    "activeDrivers": {
      ".read": "root.child('users/uid').exists() || root.child('drivers/uid').exists()",
      ".write": "root.child('users/uid').exists() || root.child('drivers/uid').exists()",
      ".indexOn": ["g"]
    },
    "users": {
      "$uid": {
        ".read": "auth !== null && auth.uid === $uid",
        ".write": "auth !== null && auth.uid === $uid",
      }
    },
    "ALL Ride Requests": {
      ".read": "root.child('users/uid').exists() || root.child('drivers/uid').exists()",
      ".write": "root.child('users/uid').exists() || root.child('drivers/uid').exists()",
    }
  }
}

数据库JSON结构

{
  "ALL Ride Requests": {
    "-NJlIOrp49pNBSuuEawT": {
      "destination": {
        "latitude": "41.929612",
        "longitude": "12.4858561"
      },
      "destinationAddress": "Duke's",
      "driverId": "waiting",
      "origin": {
        "latitude": "41.919225",
        "longitude": "12.5266267"
      },
      "originAddress": "Circonvallazione Nomentana, 270, 00162 Roma RM, Italy",
      "time": "2022-12-20 21:50:48.437521",
      "userName": "Peter Parker",
      "userPhone": "090012321354"
    },
  },
  "activeDrivers": {
    "G3OJ79KiLeMmxqoUpJ1NggIKbiF2": {
      ".priority": "sr2yt23wk8",
      "g": "sr2yt23rk8",
      "l": [
        41.926275,
        12.5376567
      ]
    },
  },
  "drivers": {
    "G3OJ79KiLeMmxqoUpJ1NggIKbiF2": {
      "earnings": "0.0",
      "email": "simo@hotmail.it",
      "id": "G3OJ79KiLeMmxqoUpJ1NggIKbiF2",
      "name": "Simone Demichele Test",
      "newRideStatus": "idle",
      "password": "testpassword",
      "phone": "3452362585",
      "token": "fFIwv1IHRv2ylXyW-qRVGQ:APA91bH7IfcNBBi7Y53wRjQKN12-nBUgFHHpf7F0LeWCstG_MIqt-mkobRN6nvUZxqbMnMlXU2yMHdE-efYykUdtcXl-91wW5rGyQcpMl6Dij6bxC8snQRkAMGBhQUmyqYW6sBhY6Ul3"
    },
  },
  "users": {
    "yHc7xseCT0QePnpolGHZvdr8ARV2": {
      "email": "peter@gmail.com",
      "id": "yHc7xseCT0QePnpolGHZvdr8ARV2",
      "name": "Peter Parker",
      "phone": "090012321354"
    }
  }
}

相关代码示例

ALL Ride Request实时更新司机位置代码

getDriversLocationUpdatesAtRealTime()
  {
    LatLng oldLatLng = LatLng(0, 0);

    streamSubscriptionDriverLivePosition = Geolocator.getPositionStream()
        .listen((Position position)
    {
      driverCurrentPosition = position;
      onlineDriverCurrentPosition = position;

      LatLng latLngLiveDriverPosition = LatLng(
        onlineDriverCurrentPosition!.latitude,
        onlineDriverCurrentPosition!.longitude,
      );

       Marker animatingMarker = Marker(
         markerId: const MarkerId("AnimatedMarker"),
         position: latLngLiveDriverPosition,
         icon: iconAnimatedMarker!,
         infoWindow: const InfoWindow(title: "Questa è la tua posizione"),
       );

      setState(() {
        CameraPosition cameraPosition = CameraPosition(target: latLngLiveDriverPosition, zoom: 15);
        newTripGoogleMapController!.animateCamera(CameraUpdate.newCameraPosition(cameraPosition));
        
        setOfMarkers.removeWhere((element) => element.markerId.value == "AnimatedMarker");
        setOfMarkers.add(animatingMarker);
      });

      oldLatLng = latLngLiveDriverPosition;
      updateDurationTimeAtRealTime();

      //updating driver location in realtime in database firebase
      Map driverLatLngDataMap =
      {
        "latitude": onlineDriverCurrentPosition!.latitude.toString(),
        "longitude": onlineDriverCurrentPosition!.longitude.toString(),
      };
      

      FirebaseDatabase.instance.ref().child("ALL Ride Requests")
          .child(widget.userRideRequestDetails!.rideRequestId!)
          .child("driverLocation")
          .set(driverLatLngDataMap);
    });
  }

activeDrivers司机上线并更新位置代码

driverIsOnlineNow() async
  {
    Position pos = await Geolocator.getCurrentPosition(
      desiredAccuracy: LocationAccuracy.high,
    );
    driverCurrentPosition = pos;

    Geofire.initialize("activeDrivers");
    
    Geofire.setLocation(
        currentFirebaseUser!.uid,
        driverCurrentPosition!.latitude,
        driverCurrentPosition!.longitude
    );

    DatabaseReference ref = FirebaseDatabase.instance.ref()
        .child("drivers")
        .child(currentFirebaseUser!.uid)
        .child("newRideStatus");

    ref.set("idle"); //searching for ride request
    ref.onValue.listen((event) { });
  }

规则失效原因及修正方案

失效原因

当前规则中root.child('users/uid').exists()是错误写法,这里的uid是字符串字面量,不是当前认证用户的UID变量,无法正确匹配数据库中的用户/司机节点,导致权限验证失败。

修正后的规则

{
  "rules": {
    "drivers": {
      "$uid": {
        ".read": "auth !== null && auth.uid === $uid",
        ".write": "auth !== null && auth.uid === $uid"
      }
    },
    "activeDrivers": {
      ".read": "auth !== null && (root.child('users').child(auth.uid).exists() || root.child('drivers').child(auth.uid).exists())",
      ".write": "auth !== null && (root.child('users').child(auth.uid).exists() || root.child('drivers').child(auth.uid).exists())",
      ".indexOn": ["g"],
      "$driverUid": {
        // 额外限制:司机只能修改自己的activeDrivers节点
        ".write": "auth !== null && auth.uid === $driverUid"
      }
    },
    "users": {
      "$uid": {
        ".read": "auth !== null && auth.uid === $uid",
        ".write": "auth !== null && auth.uid === $uid"
      }
    },
    "ALL Ride Requests": {
      ".read": "auth !== null && (root.child('users').child(auth.uid).exists() || root.child('drivers').child(auth.uid).exists())",
      ".write": "auth !== null && (root.child('users').child(auth.uid).exists() || root.child('drivers').child(auth.uid).exists())",
      "$requestId": {
        // 细化权限:用户只能修改自己发起的请求,司机只能修改分配给自己的请求
        ".write": "auth !== null && (
          (root.child('users').child(auth.uid).exists() && data.child('userName').val() === root.child('users').child(auth.uid).child('name').val()) ||
          (root.child('drivers').child(auth.uid).exists() && data.child('driverId').val() === auth.uid)
        )"
      }
    }
  }
}

修正说明

  1. 基础权限修正:将root.child('users/uid')改为root.child('users').child(auth.uid),动态获取当前认证用户的UID,正确检查用户/司机是否存在于数据库中。
  2. activeDrivers权限细化:添加$driverUid子规则,确保司机只能修改自己在activeDrivers中的位置数据,避免越权操作。
  3. ALL Ride Requests权限细化:添加$requestId子规则,限制用户只能修改自己发起的请求,司机只能修改分配给自己的请求,提升数据安全性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 09:15:32