Je ne parviens pas à faire fonctionner Firebase Storage avec des règles personnalisées et des revendications personnalisées.
Dans mon panneau d'administration Python, je fais ce qui suit pour créer l'utilisateur et attribuer une revendication client_id:
service firebase.storage { match /b/{bucket}/o { match /{environment}/{client_id}/{allPaths=**} { allow read: if request.auth.token.client_id == client_id } } }
Ensuite, pour les règles Firebase, j'essaie d'autoriser l'utilisateur à lire (ou télécharger) uniquement les fichiers lorsque le fichier est dans un sous-dossier avec le client_id:
Structure des fichiers sur le stockage:
/{environment}/{client_id}/other_folders_and_files
J'ai défini les règles de stockage suivantes:
# Standard Auth import firebase_admin from firebase_admin import db, storage, auth cred = firebase_admin.credentials.Certificate('path_to_cert_json') app = firebase_admin.initialize_app(cred, 'config') bucket = storage.bucket(app=app) # Create User auth.create_user(email=email) # Create custom claims auth.set_custom_user_claims(uid, {'client_id': client_id})
Mais cela me donne une erreur selon laquelle l'autorisation est refusée.
Qu'est-ce que je fais mal?
Remarque:
3 Réponses :
Si je ne me trompe pas, vous l'utilisez mal. Devrait être:
service firebase.storage { match /b/{bucket}/o { match /{environment}/{client_id}/{allPaths=**} { allow read: if request.auth.token.client_id == client_id } } }
Le jeton renvoie d'autres objets, comme:
Donc, pour pouvoir comparer l'ID utilisateur, vous devez utiliser request.auth.uid
. De cette façon, vous comparerez l'ID client du client. Si vous voulez jeter un oeil à la documentation , est-ce que tout request.auth
le request.auth
.
Si vous voulez votre propre jeton personnalisé, comme: request.auth.token.client_id
, vous devez le faire avec ce code en Python:
uid = 'some-uid' additional_claims = { 'client_id': your_custom_client_id } custom_token = auth.create_custom_token(uid, additional_claims)
Ensuite, vous pouvez utiliser dans vos règles de stockage:
service firebase.storage { match /b/{bucket}/o { match /{environment}/{client_id}/{allPaths=**} { allow read: if request.auth.uid == client_id } } }
Voir la documentation
Ça n'est pas correct. L'UID est un ID unique attribué par défaut par Firebase. Client_ID est une revendication personnalisée que j'ai attribuée à l'utilisateur avec un UID. Je ne veux pas définir UID = Client_ID, ce sont deux choses différentes.
Je vois ... Mais request.auth.token
n'a pas de propriété client_id
. Vous devez créer votre propre jeton personnalisé. Jetez un œil à la documentation . Vous pouvez voir comment faire cela. Si vous avez déjà fait que votre code est correct.
Ok .. mais il doit y avoir un moyen d'obtenir la revendication personnalisée dans le request.auth, ce que je recherche. Voir la partie: If the custom token contains additional claims, they can be referenced off of the auth.token (Firebase Realtime Database) or request.auth.token (Cloud Storage) object in your rules...
et sélectionnez "Règles de stockage"
Et votre réponse est exactement ce que j'ai dans ma question, non? Où est la différence?
C'est vrai haha ... Mon mauvais je n'ai pas vu la partie custom, là-bas ....
Les documents sont terribles - ils n'abordent pas du tout comment s'authentifier par rapport à n'importe quel groupe. Uniquement par utilisateur individuel. La réponse semble être des fonctions côté serveur pour définir des revendications d'authentification personnalisées, mais le document n'entre jamais dans cela.
Les revendications personnalisées sont le seul moyen de le faire pour le moment. Les règles devraient ressembler à ceci:
exports.updateUser = functions.firestore .document('users/{userId}') .onWrite( async (change, context) => { // change.before and change.after are DocumentSnapshot objects const userid=context.params.userId // (from {userId} above) const isDeleted = !change.after.exists const isNew = !change.before.exists let customClaims = {} if (!isDeleted) { let newData = change.after.data() let oldData = change.before.data() // do we need to update anything? if (isNew || newData.admin !== oldData.admin || newData.client !== oldData.client) { customClaims.admin = Boolean(newData.admin) customClaims.clientId = newData.client } } else { let oldData = change.before.data() customClaims.admin = false customClaims.clientId = null } // now do the update if needed if (customClaims !== {}) { // See https://firebase.google.com/docs/reference/admin/node/admin.auth.Auth await admin.auth().setCustomUserClaims(userid, customClaims) console.log(`Updating client for ${isNew?"new":"existing"} user ${userid}: ` + `${JSON.stringify(customClaims)}`) } })
où nous utilisons deux champs personnalisés sur le jeton d'authentification: admin
et clientId
. La fonction cloud à synchroniser avec la base de données peut ressembler à ceci:
service firebase.storage { match /b/{bucket}/o { function isAuth() { return request.auth != null && request.auth.uid != null } function isAdmin() { return isAuth() && request.auth.token.admin == true; } function clientMatch(clientId) { // expects user's "client" field to be ID of client return isAuth() && clientId == request.auth.token.clientId; } match /storage/path/{clientId}/{allPaths=**} { allow read, write: if isAdmin() || clientMatch(clientId) }
Cela s'exécute sur toute modification du document utilisateur et le synchronise avec les revendications personnalisées de l'authentification.
Par souci d'exhaustivité, il faut créer un jeton avant de définir le jeton pour l'utilisateur.
Ainsi code complet:
uid = 'some-uid' additional_claims = { 'client_id': your_custom_client_id } # First time, only once needed custom_token = auth.create_custom_token(uid, additional_claims) # Then auth.set_custom_user_claims(uid, additional_claims )
Je vais essayer ça aussi. Cela semble être la seule solution possible!
L'avez-vous résolu?
Pouvez-vous s'il vous plaît regarder ce git , peut-être que cela peut résoudre votre question
J'en ai résolu une partie: en créant des revendications personnalisées à l'aide du SDK Admin (CLI sur mon système), je peux les vérifier dans les règles de stockage. Cette partie fonctionne. Je n'ai pas encore écrit la partie pour créer une fonction côté serveur qui se déclenche sur les mises à jour de l'enregistrement utilisateur dans Firestore et crée / met à jour les revendications d'authentification personnalisées, mais je le ferai aujourd'hui. En supposant que cela fonctionne, cela semble être la seule route (quoique très détournée, longue et difficile à tester). Ce serait tellement plus facile si les règles de stockage pouvaient simplement lire les enregistrements Firestore. Maintenant, je dois tout garder à deux endroits en utilisant des fonctions côté serveur.
Après quelques heures de travail, je peux dire oui, cela fonctionne vraiment. J'ai écrit une fonction cloud déclenchée par une modification de n'importe quel document dans
users/{userId}
qui synchronise les customClaims à partir de la base de données.Pourquoi avez-vous besoin d'une fonction pour synchroniser les revendications à tout moment, ne pouvez-vous pas simplement définir la revendication une fois lors de la création de l'utilisateur comme je le fais dans ma question?
Êtes-vous sûr que la revendication a été appliquée à l'utilisateur? Vous pouvez vérifier les réclamations côté client , ce que je suggérerais simplement pour vérifier que la réclamation a été correctement appliquée. De plus, dans la ligne
auth.set_custom_user_claims(uid, {'client_id': client_id})
, d'où vient la valeur deuid
? Pouvez-vous mettre à jour votre code pour l'inclure?