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) )" } } } }
修正说明
- 基础权限修正:将
root.child('users/uid')改为root.child('users').child(auth.uid),动态获取当前认证用户的UID,正确检查用户/司机是否存在于数据库中。 - activeDrivers权限细化:添加
$driverUid子规则,确保司机只能修改自己在activeDrivers中的位置数据,避免越权操作。 - ALL Ride Requests权限细化:添加
$requestId子规则,限制用户只能修改自己发起的请求,司机只能修改分配给自己的请求,提升数据安全性。
内容的提问来源于stack exchange,提问作者Simone
相关产品推荐
相关产品推荐

