Firebase 实时安全规则:无法将 uid 与叶值进行比较
Firebase Realtime security rules: unable to compare uid with leaf value
我正在尝试配置 Firebase Realtime 以检查用户是否应该有权注册。
为此,我在每个名为“uid”的寄存器中都有一个值,其中包含可以访问它的用户的 uid。
- 数据树是“(root/)Usuaros/$userid”。
- 每个 $userid 都有一个名为“uid”的叶子,它包含一个字符串值。
按照我的逻辑,这条规则应该足够了,但它拒绝访问 Usuarios,即使它们将 uid 与 auth.uid 匹配。
{
"rules": {
"Usuarios" :{
"$usuarioPk" : {
".read": "data.child('uid').val() == auth.uid"
}
}
}
}
¿我做错了什么?
编辑:这是代码(C# - Unity 游戏引擎)。
基础ClassFirebaseTable.cs
public class FirebaseTable : MonoBehaviour
{
Firebase.Auth.FirebaseAuth auth;
Firebase.FirebaseApp app;
private void Awake()
{
}
protected UnityEvent onDataUpdate = new UnityEvent();
public string dbPath = "";
protected virtual void OnEnable()
{
IniciarListenerDB();
}
protected virtual void OnDisable()
{
DetenerListenerDB();
}
#region Iniciar/Detener Listeners
void IniciarListenerDB()
{
FirebaseDatabase.DefaultInstance
.GetReference(dbPath)
.ValueChanged += HandleValueChanged;
}
void DetenerListenerDB()
{
FirebaseDatabase.DefaultInstance
.GetReference(dbPath)
.ValueChanged -= HandleValueChanged;
}
#endregion
#region Receptor de actualizaciones
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
protected virtual void HandleValueChanged(object sender, ValueChangedEventArgs args)
{
}
#endregion
这里是childclass
public class TablaUsuarios : FirebaseTable
{
public List<Usuario> usuarios;
protected override void OnEnable()
{
base.OnEnable();
dbPath = "Usuarios";
if(usuarios == null)
{
usuarios = new List<Usuario>();
}
}
protected override void OnDisable()
{
base.OnDisable();
usuarios.Clear();
}
protected override void HandleValueChanged(object sender, ValueChangedEventArgs args)
{
DataSnapshot dataSnapshot = args.Snapshot;
if(args.DatabaseError != null)
{
Debug.LogError(args.DatabaseError.Message);
}
List<Usuario> entitiesDB = DataSnapshotToList(dataSnapshot);
usuarios = entitiesDB;
//UpdatePublicList(entitiesDB, ref usuarios);
}
List<Usuario> DataSnapshotToList(DataSnapshot dataSnapshot)
{
List<Usuario> result = new List<Usuario>();
foreach(var children in dataSnapshot.Children)
{
if (children.Value is IDictionary<string, object> variables)
{
Debug.Log(dataSnapshot.GetRawJsonValue());
Usuario entity = new Usuario();
entity.pk = (string)variables["pk"];
entity.uid = (string)variables["uid"];
entity.nombre = (string)variables["nombre"];
entity.apellidos = (string)variables["apellidos"];
entity.email = (string)variables["email"];
entity.telefono = (string)variables["telefono"];
entity.tipoUsuario = (string)variables["tipoUsuario"];
entity.skContrato = (string)variables["skContrato"];
result.Add(entity);
}
}
return result;
}
void UpdatePublicList(List<Usuario> firebaseEntities, ref List<Usuario> localEntities)
{
List<Usuario> usuariosToCreate = new List<Usuario>(); // Añadiremos los usuarios que deben ser creados
List<Usuario> usuariosToUpdate = new List<Usuario>(); // Añadiremos los usuarios que deben ser actualizados
List<Usuario> usuariosToDelete = new List<Usuario>(); // Añadiremos los usuarios que deben ser eliminados
foreach (var element in localEntities) // Creamos una lista con los usuarios a eliminar
{
usuariosToDelete.Add(element);
}
foreach(var firebaseElement in firebaseEntities) // Iteramos por la lista publica de usuarios
{
if (!UsuarioExist(firebaseElement.pk, localEntities)) // Si no la encontramos
{
usuariosToCreate.Add(firebaseElement);
}
else if (UsuarioExist(firebaseElement.pk, localEntities)) // Si la encontramos pero ha cambiado
{
usuariosToUpdate.Add(firebaseElement);
}
}
foreach(var localElement in localEntities)
{
if(!UsuarioExist(localElement.pk, firebaseEntities))
{
usuariosToDelete.Add(localElement);
}
}
for(int i = 0; i < usuariosToDelete.Count; i++)
{
usuarios.Remove(FindUsuario(usuariosToDelete[i].pk, usuarios));
}
for (int i = 0; i < usuariosToCreate.Count; i++)
{
usuarios.Add(usuariosToCreate[i]);
}
for (int i = 0; i < usuariosToUpdate.Count; i++)
{
FindUsuario(usuariosToUpdate[i].pk, usuarios).CopyDataFrom(usuariosToUpdate[i]);
}
}
public Usuario FindUsuario(string pk, List<Usuario> data)
{
foreach(var usuario in usuarios)
{
if(usuario.Pk == pk)
{
return usuario;
}
}
return null;
}
public bool UsuarioExist(string pk, List<Usuario> data)
{
if(FindUsuario(pk, data) != null)
{
return true;
}
return false;
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
和错误日志:
This client does not have permission to perform this operation.
UnityEngine.Debug:LogError (object)
TablaUsuarios:HandleValueChanged (object,Firebase.Database.ValueChangedEventArgs) (at Assets/Scripts/Tablas Firebase/NuevoSistema/Tables/TablaUsuarios.cs:36)
Firebase.Database.Internal.InternalValueListener/c__AnonStorey1:<>m__0 () (at Z:/tmp/tmp.gpjxyegeCh/firebase/database/client/unity/proxy/InternalValueListener.cs:72)
Firebase.ExceptionAggregator:Wrap (System.Action) (at Z:/tmp/tmp.AqqnQIVt80/firebase/app/client/unity/src/Platform/ExceptionAggregator.cs:112)
Firebase.Database.Internal.InternalValueListener:OnCancelledHandler (int,Firebase.Database.Internal.Error,string) (at Z:/tmp/tmp.gpjxyegeCh/firebase/database/client/unity/proxy/InternalValueListener.cs:65)
Firebase.AppUtil:PollCallbacks () (at Z:/tmp/tmp.RYyft9kBZb/firebase/app/client/unity/proxy/AppUtil.cs:32)
Firebase.Platform.FirebaseAppUtils:PollCallbacks () (at Z:/tmp/tmp.RYyft9kBZb/firebase/app/client/unity/proxy/FirebaseAppUtils.cs:33)
Firebase.Platform.FirebaseHandler:Update () (at Z:/tmp/tmp.AqqnQIVt80/firebase/app/client/unity/src/Unity/FirebaseHandler.cs:208)
Firebase.Platform.FirebaseMonoBehaviour:Update () (at Z:/tmp/tmp.AqqnQIVt80/firebase/app/client/unity/src/Unity/FirebaseMonoBehaviour.cs:45)
您的代码正在尝试读取 /Usarios
节点。但是如果我们查看规则,没有人有权读取 /Usarios
节点,因此读取操作会(正确地)被拒绝。
此错误的一个常见来源是 rules do not filter data。相反,规则仅检查是否允许您尝试执行的操作。
如果您想安全地过滤数据,则必须在规则和代码中对条件进行编码,如 query based rules 上的文档所示。这可能是:
"Usarios": {
".read": "auth.uid != null &&
query.orderByChild == 'uid' &&
query.equalTo == auth.uid" // restrict profile access to owner of the profile
}
我正在尝试配置 Firebase Realtime 以检查用户是否应该有权注册。
为此,我在每个名为“uid”的寄存器中都有一个值,其中包含可以访问它的用户的 uid。
- 数据树是“(root/)Usuaros/$userid”。
- 每个 $userid 都有一个名为“uid”的叶子,它包含一个字符串值。
按照我的逻辑,这条规则应该足够了,但它拒绝访问 Usuarios,即使它们将 uid 与 auth.uid 匹配。
{
"rules": {
"Usuarios" :{
"$usuarioPk" : {
".read": "data.child('uid').val() == auth.uid"
}
}
}
}
¿我做错了什么?
编辑:这是代码(C# - Unity 游戏引擎)。
基础ClassFirebaseTable.cs
public class FirebaseTable : MonoBehaviour
{
Firebase.Auth.FirebaseAuth auth;
Firebase.FirebaseApp app;
private void Awake()
{
}
protected UnityEvent onDataUpdate = new UnityEvent();
public string dbPath = "";
protected virtual void OnEnable()
{
IniciarListenerDB();
}
protected virtual void OnDisable()
{
DetenerListenerDB();
}
#region Iniciar/Detener Listeners
void IniciarListenerDB()
{
FirebaseDatabase.DefaultInstance
.GetReference(dbPath)
.ValueChanged += HandleValueChanged;
}
void DetenerListenerDB()
{
FirebaseDatabase.DefaultInstance
.GetReference(dbPath)
.ValueChanged -= HandleValueChanged;
}
#endregion
#region Receptor de actualizaciones
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="args"></param>
protected virtual void HandleValueChanged(object sender, ValueChangedEventArgs args)
{
}
#endregion
这里是childclass
public class TablaUsuarios : FirebaseTable
{
public List<Usuario> usuarios;
protected override void OnEnable()
{
base.OnEnable();
dbPath = "Usuarios";
if(usuarios == null)
{
usuarios = new List<Usuario>();
}
}
protected override void OnDisable()
{
base.OnDisable();
usuarios.Clear();
}
protected override void HandleValueChanged(object sender, ValueChangedEventArgs args)
{
DataSnapshot dataSnapshot = args.Snapshot;
if(args.DatabaseError != null)
{
Debug.LogError(args.DatabaseError.Message);
}
List<Usuario> entitiesDB = DataSnapshotToList(dataSnapshot);
usuarios = entitiesDB;
//UpdatePublicList(entitiesDB, ref usuarios);
}
List<Usuario> DataSnapshotToList(DataSnapshot dataSnapshot)
{
List<Usuario> result = new List<Usuario>();
foreach(var children in dataSnapshot.Children)
{
if (children.Value is IDictionary<string, object> variables)
{
Debug.Log(dataSnapshot.GetRawJsonValue());
Usuario entity = new Usuario();
entity.pk = (string)variables["pk"];
entity.uid = (string)variables["uid"];
entity.nombre = (string)variables["nombre"];
entity.apellidos = (string)variables["apellidos"];
entity.email = (string)variables["email"];
entity.telefono = (string)variables["telefono"];
entity.tipoUsuario = (string)variables["tipoUsuario"];
entity.skContrato = (string)variables["skContrato"];
result.Add(entity);
}
}
return result;
}
void UpdatePublicList(List<Usuario> firebaseEntities, ref List<Usuario> localEntities)
{
List<Usuario> usuariosToCreate = new List<Usuario>(); // Añadiremos los usuarios que deben ser creados
List<Usuario> usuariosToUpdate = new List<Usuario>(); // Añadiremos los usuarios que deben ser actualizados
List<Usuario> usuariosToDelete = new List<Usuario>(); // Añadiremos los usuarios que deben ser eliminados
foreach (var element in localEntities) // Creamos una lista con los usuarios a eliminar
{
usuariosToDelete.Add(element);
}
foreach(var firebaseElement in firebaseEntities) // Iteramos por la lista publica de usuarios
{
if (!UsuarioExist(firebaseElement.pk, localEntities)) // Si no la encontramos
{
usuariosToCreate.Add(firebaseElement);
}
else if (UsuarioExist(firebaseElement.pk, localEntities)) // Si la encontramos pero ha cambiado
{
usuariosToUpdate.Add(firebaseElement);
}
}
foreach(var localElement in localEntities)
{
if(!UsuarioExist(localElement.pk, firebaseEntities))
{
usuariosToDelete.Add(localElement);
}
}
for(int i = 0; i < usuariosToDelete.Count; i++)
{
usuarios.Remove(FindUsuario(usuariosToDelete[i].pk, usuarios));
}
for (int i = 0; i < usuariosToCreate.Count; i++)
{
usuarios.Add(usuariosToCreate[i]);
}
for (int i = 0; i < usuariosToUpdate.Count; i++)
{
FindUsuario(usuariosToUpdate[i].pk, usuarios).CopyDataFrom(usuariosToUpdate[i]);
}
}
public Usuario FindUsuario(string pk, List<Usuario> data)
{
foreach(var usuario in usuarios)
{
if(usuario.Pk == pk)
{
return usuario;
}
}
return null;
}
public bool UsuarioExist(string pk, List<Usuario> data)
{
if(FindUsuario(pk, data) != null)
{
return true;
}
return false;
}
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
}
和错误日志:
This client does not have permission to perform this operation. UnityEngine.Debug:LogError (object) TablaUsuarios:HandleValueChanged (object,Firebase.Database.ValueChangedEventArgs) (at Assets/Scripts/Tablas Firebase/NuevoSistema/Tables/TablaUsuarios.cs:36) Firebase.Database.Internal.InternalValueListener/c__AnonStorey1:<>m__0 () (at Z:/tmp/tmp.gpjxyegeCh/firebase/database/client/unity/proxy/InternalValueListener.cs:72) Firebase.ExceptionAggregator:Wrap (System.Action) (at Z:/tmp/tmp.AqqnQIVt80/firebase/app/client/unity/src/Platform/ExceptionAggregator.cs:112) Firebase.Database.Internal.InternalValueListener:OnCancelledHandler (int,Firebase.Database.Internal.Error,string) (at Z:/tmp/tmp.gpjxyegeCh/firebase/database/client/unity/proxy/InternalValueListener.cs:65) Firebase.AppUtil:PollCallbacks () (at Z:/tmp/tmp.RYyft9kBZb/firebase/app/client/unity/proxy/AppUtil.cs:32) Firebase.Platform.FirebaseAppUtils:PollCallbacks () (at Z:/tmp/tmp.RYyft9kBZb/firebase/app/client/unity/proxy/FirebaseAppUtils.cs:33) Firebase.Platform.FirebaseHandler:Update () (at Z:/tmp/tmp.AqqnQIVt80/firebase/app/client/unity/src/Unity/FirebaseHandler.cs:208) Firebase.Platform.FirebaseMonoBehaviour:Update () (at Z:/tmp/tmp.AqqnQIVt80/firebase/app/client/unity/src/Unity/FirebaseMonoBehaviour.cs:45)
您的代码正在尝试读取 /Usarios
节点。但是如果我们查看规则,没有人有权读取 /Usarios
节点,因此读取操作会(正确地)被拒绝。
此错误的一个常见来源是 rules do not filter data。相反,规则仅检查是否允许您尝试执行的操作。
如果您想安全地过滤数据,则必须在规则和代码中对条件进行编码,如 query based rules 上的文档所示。这可能是:
"Usarios": {
".read": "auth.uid != null &&
query.orderByChild == 'uid' &&
query.equalTo == auth.uid" // restrict profile access to owner of the profile
}