Unable to get client data to display [firestore]

2019-08-24 04:57发布

问题:

My database is setup as /clients and uses firebase auth to handle users. I want to make it so users can only see, edit, and delete client data they created. The current firestore security rule is.

[code]service cloud.firestore {
  match /databases/{database}/documents {
    // Make sure the uid of the requesting user matches name of the user
    // document. The wildcard expression {userId} makes the userId variable
    // available in rules.
    match /clients/{userId} {
      allow read, update, delete: if request.auth.uid == userId;
      allow create: if request.auth.uid != null;
    }
  }
}[/code]

With this rule users are able to add new clients into the database, however the clients on the website are not showing. I have the code setup so that when a user adds a client it attaches the users UID to the client under 'userId'. The code to display the clients is

[code]<tbody>
                    {clients.map(client => (
                        <tr key={client.id}>
                            <td>{client.firstName} {client.lastName}</td>
                            <td>{client.dateCreated}</td>
                            <td><a href={`tel:${client.phone}`}>{client.phone}</a></td>
                            <td>
                                <Link to={`/client/${client.id}`} className="btn btn-secondary btn-sm">
                                    <i className="fas fa-arrow-circle-right"></i> Details
                                </Link>
                            </td>
                        </tr>
                    ))}
                 </tbody>

[/code]

I'm not sure what I'm doing wrong, is it the security rules or how I'm choosing to display the data?

回答1:

What I understand is that you have a clients collection and a users collection. Users can create clients and are only able to see/edit/delete clients they've created right ? If so, simply add a createdBy (could be anything) field that contains the user uid who created the specific client and check if this field is equal to the uid you get from the auth object :

service cloud.firestore {
  match /databases/{database}/documents {
    match /clients/{clientId} {
      // only user who created the client can read/update/delete it
      allow read, update, delete: if resource.data.createdBy == request.auth.uid;
      // logged user only can create a client
      allow create: if request.auth.uid != null;
    }
  }
}

The wildcard {clientId} is just here to say "hey, this rule applies for any document under clients/ collection". You can get the data stored in a document thanks to the resource.data object.

Everything is listed in the documentation : https://firebase.google.com/docs/firestore/security/get-started



回答2:

I was able to get my result but not via security rules. After adjusting the security rules and my database variables so that users id is attached to the data they add, I attempted the rule suggested by @firebaser. I was able to create clients under that rule as mentioned above however, I couldn't view them and in the console I got "Error with profile listener: Missing or insufficient permissions. FirebaseError: Missing or insufficient permissions".

Based on the error it looked like I'd have to edit one of the firebase files in the node module of my project folder. I didn't want to risk modifying those files so instead of using the security rules to filter data, I just altered how the client data gets displayed. I added a .filter before the .map function so that it will only show the clients linked to the users id. While my security rules only allows logged in users to read and write data. [code]

<tbody>
            {clients.filter(client => client.userId === firebase.auth().currentUser.uid).map(client => (
                <tr key={client.id}>
                    <td>{client.firstName} {client.lastName}</td>
                    <td>{client.dateCreated}</td>
                    <td><a href={`tel:${client.phone}`}>{client.phone}</a></td>
                    <td>
                        <Link to={`/client/${client.id}`} className="btn btn-secondary btn-sm">
                            <i className="fas fa-arrow-circle-right"></i> Details
                        </Link>
                    </td>
                </tr>
            ))}
         </tbody>

[/code]

I can't really tell anyone how secure this method would be, but it works.