¿Obtener la identificación de usuario de un disparador de Firestore en Cloud Functions para Firebase?
google-cloud-functions google-cloud-firestore (7)
Como ya se sugirió anteriormente, la solución será agregar un campo user_id con los datos en sí y luego leerlo en el servidor.
El inconveniente de este enfoque será una laguna de seguridad. Como no estamos verificando la identificación de usuario en el servidor, cualquier otro usuario podrá suplantar a otros usuarios enviando su identificación con los datos.
Para aplicaciones críticas de seguridad, la solución para esto será usar reglas de seguridad para verificar que se ha enviado el user_id correcto con los datos
allow write: if resource.data.user_id == request.auth.uid;
En el siguiente ejemplo, ¿hay alguna forma de obtener la identificación de usuario (uid) del usuario que escribió a ''Offers / {offerId}''? Traté de hacer lo descrito here pero no funciona en Firestore.
exports.onNewOffer = functions.firestore
.document(''offers/{offerId}'')
.onCreate(event => {
...
});
De qué se trata
snap._fieldsProto.uid.stringValue
Ejemplo:
exports.hello = functions.firestore.document(''hello/{worldId}'').onCreate((snap, context) => {
console.log(snap._fieldsProto.uid.stringValue)
});
Esto debería funcionar:
exports.newMessage = functions.firestore
.document(''groups/messages/{messageId}'')
.onCreate((snap, context) => {
var fromId = snap.data().fromId;
Estuve luchando sobre esto por un tiempo y finalmente contacté al Soporte de firebase:
event.auth.uid
no está definido en el objeto de evento para los desencadenantes de la base de datos del
event.auth.uid
de incendios.
(Funciona para los desencadenadores de bases de datos en tiempo real)
Cuando
console.log(event)
no puedo encontrar ninguna
auth
en la salida.
La respuesta oficial de soporte:
Lo sentimos, la autenticación aún no se ha agregado en el SDK de Firestore. Lo tenemos listado en las siguientes características.
Esté atento a nuestras notas de lanzamiento para cualquier actualización adicional.
Espero que esto ahorre a alguien unas horas.
Hasta que esto se agregue a las funciones de firestore, una solución alternativa es agregar
user_id
como campo al crear un documento y luego eliminarlo.
Luego puede tomarlo en la función onCreate y luego, después de usarlo para lo que lo necesita, mientras aún está en la función, simplemente elimine el campo de ese documento.
Puede obtener el tokenId del usuario con sesión iniciada actual llamando a getIdToken () en el usuario: https://firebase.google.com/docs/reference/functions/functions.auth.UserInfo
Resumen de cómo resolví esta / una solución viable:
En el cliente
Agregue el uid del usuario conectado / actual (por ejemplo, como
creatorId
) a la entidad que está creando.
Acceda a este uid almacenando el objeto de usuario
firebase.auth().onAuthStateChanged()
en el estado de su aplicación.
En Firebase Firestore / Database
Agregue una regla de seguridad para
create
para validar que el valor de
creatorId
proporcionado por el cliente es el mismo que el del usuario autenticado;
Ahora sabe que el cliente no está falsificando el
creatorId
y puede confiar en este valor en otro lugar.
p.ej
match /entity/{entityId} {
allow create: if madeBySelf();
}
function madeBySelf() {
return request.auth.uid == request.resource.data.creatorId;
}
En funciones de Firebase
Agregue un activador
onCreate
a su tipo de entidad creado para usar el
creatorId
proporcionado por el cliente y ahora validado para buscar la información de perfil del usuario creador y asociar / agregar esta información al nuevo documento de entidad.
Esto se puede lograr mediante:
-
Crear una colección de
users
y documentos deuser
individuales cuando se crean nuevas cuentas, y llenar el nuevo documento deuser
con campos útiles para la aplicación (displayName
ejemplo,displayName
). Esto es necesario porque los campos expuestos por el sistema de autenticación de Firebase son insuficientes para los usos de las aplicaciones de consumo (por ejemplo,displayName
yavatarURL
no están expuestos), por lo que no puede confiar en buscar la información del usuario de esa manera.por ejemplo (usando ES6)
import * as functions from ''firebase-functions''
import * as admin from ''firebase-admin''
const APP = admin.initializeApp()
export const createUserRecord = functions.auth.user()
.onCreate(async (userRecord, context) => {
const userDoc = {
id: userRecord.uid,
displayName: userRecord.displayName || "No Name",
avatarURL: userRecord.photoURL || '''',
}
return APP.firestore().collection(''users'').doc(userRecord.uid).set(userDoc)
})
-
Ahora que tiene un valor
creatorId
validado y objetos deuser
útiles, agregue un activadoronCreate
a su tipo de entidad (o todas sus entidades creadas) para buscar la información del usuario creador y agregarla al objeto creado.
export const addCreatorToDatabaseEntry = functions.firestore
.document(''<your entity type here>/{entityId}'')
.onCreate(async (snapshot, context) => {
const userDoc = await APP.firestore().collection(''users'').doc(snapshot.data().creatorId).get()
return snapshot.ref.set({ creator: userDoc.data() }, { merge: true })
})
Esto claramente lleva a una gran cantidad de datos de información de usuario duplicados en todo su sistema, y hay un poco de limpieza que puede hacer (''creatorId` está duplicado en la entidad creada en la implementación anterior), pero ahora es muy fácil de mostrar quién creó qué a través de su aplicación y parece ser ''la forma de Firebase''.
Espero que esto ayude. He descubierto que Firebase es súper sorprendente en algunos aspectos y hace que algunas cosas normalmente fáciles (como esta) sean más difíciles de lo que deberían ser; a fin de cuentas, aunque soy un gran admirador.