简体   繁体   English

如何在 Cloud Functions 存储触发器中获取经过身份验证的 Firebase 用户的 uid

[英]How to get the uid of the authenticated Firebase user in a Cloud Functions storage trigger

Background: I'm using Firebase Cloud Functions, the new Firestore Database, and storage bucket with an Android client.背景:我在 Android 客户端上使用 Firebase Cloud Functions、新的 Firestore 数据库和存储桶。

What I want to accomplish: When a user uploads a picture to a storage bucket, I want to use cloud functions to get the file path/link to the image location in the storage bucket and store this string as a new document under a new collection called "pictures" under the currently logged in user's document in Firestore.我想完成的:当用户上传图片到存储桶时,我想使用云函数获取存储桶中图片位置的文件路径/链接,并将此字符串作为新文档存储在新集合下在 Firestore 中当前登录的用户文档下称为“图片”。

That way, I can see the images each user has uploaded directly in Firestore and it makes it easier to pull a specific user's images down to the Android client.这样,我可以直接在 Firestore 中查看每个用户上传的图像,并且可以更轻松地将特定用户的图像下拉到 Android 客户端。

What I've completed so far: 1. When a user logs in for the first time, it creates a user doc in the new Firestore Database.到目前为止我完成的工作: 1. 当用户第一次登录时,它会在新的 Firestore 数据库中创建一个用户文档。 2. A logged in user can upload an image to a storage bucket. 2. 登录用户可以上传图片到存储桶。 3. Using Firebase Cloud Functions, I managed to get the file path/link of the storage location as follows: 3.使用Firebase Cloud Functions,我设法获取存储位置的文件路径/链接如下:

 /** * When a user selects a profile picture on their device during onboarding, * the image is sent to Firebase Storage from a function running on their device. * The cloud function below returns the file path of the newly uploaded image. */ exports.getImageStorageLocationWhenUploaded = functions.storage.object().onFinalize((object) => { const filePath = object.name; // File path in the bucket. const contentType = object.contentType; // File content type. // Exit if this is triggered on a file that is not an image. if (!contentType.startsWith('image/')) { console.log('This is not an image.'); return null; } console.log(filePath); });

Question: How do I get the currently logged in user and store this user's uploaded image file path/link as a new doc under this logged in user's documents within the Firestore database using Cloud Functions?问题:如何使用 Cloud Functions 获取当前登录的用户并将此用户上传的图像文件路径/链接作为新文档存储在 Firestore 数据库中此登录用户的文档下?

Currently, with Cloud Storage triggers, you don't have access to authenticated user information.目前,使用 Cloud Storage 触发器,您无权访问经过身份验证的用户信息。 To work around that, you'll have to do something like embed the uid in the path of the file, or add the uid as metadata in the file upload.要解决这个问题,您必须执行一些操作,例如将 uid 嵌入到文件路径中,或者将 uid 添加为文件上传中的元数据。

I had a similar problem where I wanted to associate a user uploaded image with his/her uid.我有一个类似的问题,我想将用户上传的图像与他/她的 uid 相关联。 I found an elegant solution that does not necessarily requires inserting the uid in the path of the file or even adding it as metadata in the file upload.我找到了一个优雅的解决方案,它不一定需要在文件路径中插入 uid,甚至不需要将其作为元数据添加到文件上传中。 In fact, the uid is securely transmitted to the database via the standard idToken encoding.实际上,uid 通过标准的 idToken 编码安全地传输到数据库。 This example employs a modified version of the generate-thumbnail cloud function example (found here ) which I believe the author of the question was using/alluding to.此示例采用了生成缩略图云函数示例(可在此处找到)的修改版本,我相信问题的作者正在使用/暗指该示例。 Here are the steps:以下是步骤:

Client side:客户端:

  1. Create a trigger function that will run once the user uploaded the image - this functions will simply call the cloud function directly (via the httpsCallable method).创建一个触发器函数,该函数将在用户上传图像后运行- 该函数将直接调用云函数(通过 httpsCallable 方法)。 The cloud function will receive the user uid (idToken encoded), along with any image metadata you may wish to send.云函数将接收用户 uid(idToken 编码)以及您可能希望发送的任何图像元数据。 The cloud function will then return a signed URL of the image.然后,云函数将返回图像的签名 URL。
const generateThumbnail = firebase.functions().httpsCallable('generateThumbnail');
const getImageUrl = (file) => {
  firebase.auth().currentUser.getIdToken(true)
    .then((idToken) => generateThumbnail({ 
      idToken, 
      imgName: file.name, 
      contentType: file.type 
    }))
    .then((data) => {   
      // Here you can save your image url to the app store, etc. 
      // An example of a store action: 
      // setImageUrl(data.data.url);
    })
    .catch((error) => { 
      console.log(error); 
  })
}
  1. Create an image upload function – this is a standard file upload handling function;创建图片上传函数——这是一个标准的文件上传处理函数; you can make the uid part of storage file path location for the image (if you want to) but you can also trigger a firebase function once the image has been uploaded.您可以将 uid 部分设为图像的存储文件路径位置(如果您愿意),但您也可以在图像上传后触发 firebase 功能。 This is possible using the 3rd parameter of the on method.这可以使用on方法的第三个参数来实现。 Include the trigger function above as the 3rd argument in here.在此处包含上面的触发器函数作为第三个参数。
// Function triggered on file import status change from the <input /> tag
const createThumbnail = (e) => {
  e.persist();
  let file = e.target.files[0];
  // If you are using a non default storage bucket use this
  // let storage = firebase.app().storage('gs://your_non_default_storage_bucket');
  // If you are using the default storage bucket use this
  let storage = firebase.storage();
  // You can add the uid in the image file path store location but this is optional
  let storageRef = storage.ref(`${uid}/thumbnail/${file.name}`);
  storageRef.put(file).on('state_changed', (snapshot) => {}, (error) => {
    console.log('Something went wrong! ', error); 
  }, getImageUrl(file));
}

Server side:服务器端:

  1. Create a cloud function to convert the image into a resized thumbnail and generate a signed URL – this cloud function takes the image from storage, converts it into a thumbnail (basically reduces its dimensions but keeps initial aspect ratio) using ImageMagick (this is installed by default on all cloud function instances).创建一个云函数将图像转换为调整大小的缩略图并生成一个签名的 URL——这个云函数从存储中获取图像,使用 ImageMagick(这由安装默认在所有云函数实例上)。 It then generates a signed URL of the image location and returns it to the client side.然后它生成图像位置的签名 URL 并将其返回给客户端。
// Import your admin object with the initialized app credentials
const mkdirp = require('mkdirp');
const spawn = require('child-process-promise').spawn;
const path = require('path');
const os = require('os');
const fs = require('fs');

// Max height and width of the thumbnail in pixels.
const THUMB_MAX_HEIGHT = 25;
const THUMB_MAX_WIDTH = 125;
// Thumbnail prefix added to file names.
const THUMB_PREFIX = 'thumb_';

async function generateThumbnail(data) {
  
  // Get the user uid from IdToken
  const { idToken, imgName, contentType } = data;
  const decodedIdToken = await admin.auth().verifyIdToken(idToken);
  const uid = decodedIdToken.uid;
  
  // File and directory paths.
  const filePath = `${uid}/thumbnail/${imgName}`;
  const fileDir = path.dirname(filePath);
  const fileName = path.basename(filePath);
  const thumbFilePath = path.normalize(path.join(fileDir, `${THUMB_PREFIX}${fileName}`));
  const tempLocalFile = path.join(os.tmpdir(), filePath);
  const tempLocalDir = path.dirname(tempLocalFile);
  const tempLocalThumbFile = path.join(os.tmpdir(), thumbFilePath);

  // Exit if this is triggered on a file that is not an image.
  if (!contentType.startsWith('image/')) {
    return console.log('This is not an image.');
  }

  // Exit if the image is already a thumbnail.
  if (fileName.startsWith(THUMB_PREFIX)) {
    return console.log('Already a Thumbnail.');
  }

  // Cloud Storage files.
  const bucket = initDb.storage().bucket('your_bucket_if_non_default');
  const originalFile = bucket.file(filePath);
  
  // Create the temp directory where the storage file will be downloaded.
  // But first check to see if it does not already exists
  if (!fs.existsSync(tempLocalDir)) await mkdirp(tempLocalDir);

  // Download original image file from bucket.
  await originalFile.download({ destination: tempLocalFile });
  console.log('The file has been downloaded to', tempLocalFile);

  // Delete the original image file as it is not needed any more
  await originalFile.delete();
  console.log('Delete the original file as it is not needed any more');
  
  // Generate a thumbnail using ImageMagick.
  await spawn('convert', [ tempLocalFile, '-thumbnail', 
    `${THUMB_MAX_WIDTH}x${THUMB_MAX_HEIGHT}>`, tempLocalThumbFile], 
    { capture: ['stdout', 'stderr'] }
  );
  console.log('Thumbnail created at', tempLocalThumbFile);
  
  // Uploading the Thumbnail.
  const url = await uploadLocalFileToStorage(tempLocalThumbFile, thumbFilePath, 
  contentType);
  console.log('Thumbnail uploaded to Storage at', thumbFilePath);
  
  // Once the image has been uploaded delete the local files to free up disk space.
  fs.unlinkSync(tempLocalFile);
  fs.unlinkSync(tempLocalThumbFile);
  
  // Delete the uid folder from temp/pdf folder
  fs.rmdirSync(tempLocalDir);

  await admin.database().ref(`users/${uid}/uploaded_images`).update({ logoUrl: url[0] });
  return { url: url[0] };
}

// Upload local file to storage
exports.uploadLocalFileToStorage = async (tempFilePath, storageFilePath, 
  contentType, customBucket = false) => {
  let bucket = initDb.storage().bucket();
  if (customBucket) bucket = initDb.storage().bucket(customBucket);
  const file = bucket.file(storageFilePath);
  try {
    // Check if file already exists; if it does delete it
    const exists = await file.exists();
    if (exists[0]) await file.delete();
  
    // Upload local file to the bucket
    await bucket.upload(tempFilePath, {
      destination: storageFilePath,
      metadata: { cacheControl: 'public, max-age=31536000', contentType }
    });
    const currentDate = new Date();
    const timeStamp = currentDate.getTime();
    const newDate = new Date(timeStamp + 600000);
    const result = await file.getSignedUrl({
      action: 'read',
      expires: newDate
    });
    return result;
  } catch (e) {
    throw new Error("uploadLocalFileToStorage failed: " + e);
  }
};

if (firebase.auth().currentUser !== null) 
        console.log("user id: " + firebase.auth().currentUser.uid);

Simple way to get userid of a user.获取用户的用户 ID 的简单方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Firebase:如何获取其他用户的uid? - Firebase : How to get other user's uid? 如何从android上的firebase获取用户uid? - How to get user uid from firebase on android? 使用用户的UID发送Firebase云消息 - Sending Firebase Cloud Message using UID of user 如何使用Firebase电子邮件/密码身份验证获取UID并添加用户信息 - How to get UID and add user information with Firebase email/password authentication 如何获取通过google登录的用户的firebase UID? - how to get the firebase UID of the user who logged in via google? 每当用户注册到我的应用程序时,如何使用Cloud Functions for Firebase发出通知 - How do i give notification every time user get registered to my app, using Cloud Functions for Firebase 如何在Android Firebase存储和Cloud Firestore上为用户编写规则 - How to write rules for user on android firebase storage and cloud firestore 无法从云端点获取经过身份验证的用户 - Unable to get authenticated user from cloud endpoints Firebase 云存储函数触发器——为新创建的文件确定用户的 ID 令牌 - Firebase Cloud Storage Function Trigger -- Determine User's ID Token for Newly Created File 使用UID将数据从Firebase存储获取到android studio - Get data from firebase storage to android studio using the UID
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM