You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于JWT认证的Google Drive文件上传与权限控制实现求助

Google Drive文件上传与权限配置解决方案

问题背景

需要实现以下功能:

  • 前端上传视频、PDF、图片等文件至Google Drive,上传时自动创建对应文件夹
  • 为指定的3个邮箱赋予该文件夹的仅查看权限,非指定邮箱无法访问
  • 结合JWT登录系统,前端通过解析JWT获取用户邮箱,判断是否具备访问权限,进而展示对应文件

现有代码无法完成权限添加操作,以下是完整解决方案:


用户原有代码

const { google } = require('googleapis');
const googleScope = ['https://www.googleapis.com/auth/drive']
const googleKey = process.env.GOOGLE_KEY;
const fs = require('fs')
const express = require('express');
const router = express.Router();

const Multer = require("multer");


const authenticateGoogle = () => {
  const auth = new google.auth.GoogleAuth({
    keyFile: __dirname + "/book-375320-56d9bd2b6239.json",
    scopes: googleScope,
  });
  return auth;
};

const multer = Multer({
  storage: Multer.diskStorage({
    destination: function (req, file, callback) {
      callback(null, `${__dirname}/fff`);
    },
    filename: function (req, file, callback) {
      callback(null, file.fieldname + "_" + Date.now() + "_" + file.originalname);
    },
  }),
  limits: {
    fileSize: 5 * 1024 * 1024,
  },
});

const uploadToGoogleDrive = async (file , auth ) => {
    const fileMetadata = {
      name: file.originalname,
      parents: ["1PLzjikkBXnSpBNi7OZxh3-XhEAIji_94"]
    };
  
    const media = {
      mimeType: file.mimetype,
      body: fs.createReadStream(file.path),
    };
  
    const driveService = google.drive({ version: "v3", auth });
  
    const response = await driveService.files.create({
      requestBody: fileMetadata,
      media: media,
      fields: "id",
    });
    return response;
};


const deleteFile = (filePath) => {
    fs.unlink(filePath, () => {
      console.log("file deleted");
    });
};

router.post("/uploadGD", multer.single("file") , async (req , res , next ) => {
    try {
      if (!req.file) {
        res.status(400).send("No file uploaded.");
        return;
      }
      const auth = authenticateGoogle();
      const response = await uploadToGoogleDrive(req.file, auth);
      deleteFile(req.file.path);
      res.status(200).json({ response });
    } catch (err) {
      console.log(err);
}});

module.exports = router;

完整修改方案

1. 新增文件夹创建函数

先创建专属文件夹,再将文件上传至该文件夹下,避免文件混乱:

const createFolder = async (folderName, auth) => {
  const driveService = google.drive({ version: "v3", auth });
  const folderMetadata = {
    name: folderName,
    mimeType: 'application/vnd.google-apps.folder'
  };
  const response = await driveService.files.create({
    requestBody: folderMetadata,
    fields: 'id'
  });
  return response.data.id;
};

2. 新增权限设置函数

为文件夹添加指定邮箱的查看权限,同时移除可能的公开访问权限,确保仅指定用户可访问:

const addFolderPermissions = async (folderId, emails, auth) => {
  const driveService = google.drive({ version: "v3", auth });
  
  // 移除默认公开权限(可选,确保文件夹私有)
  const permissions = await driveService.permissions.list({
    fileId: folderId,
    fields: 'permissions(id,type,role)'
  });
  for (const perm of permissions.data.permissions) {
    if (perm.type === 'anyone' || perm.role === 'writer') {
      await driveService.permissions.delete({
        fileId: folderId,
        permissionId: perm.id
      });
    }
  }

  // 为每个邮箱添加只读权限
  for (const email of emails) {
    await driveService.permissions.create({
      fileId: folderId,
      requestBody: {
        type: 'user',
        role: 'reader',
        emailAddress: email
      },
      fields: 'id'
    });
  }
};

3. 修改上传路由逻辑

整合文件夹创建、文件上传、权限配置流程,同时接收前端传来的邮箱列表:

router.post("/uploadGD", multer.single("file"), async (req, res, next) => {
  try {
    if (!req.file) {
      return res.status(400).send("No file uploaded.");
    }
    // 获取前端传来的授权邮箱列表
    const { emails } = req.body;
    if (!emails || !Array.isArray(emails) || emails.length === 0) {
      return res.status(400).send("Please provide at least one authorized email.");
    }

    const auth = authenticateGoogle();
    // 创建专属文件夹(用时间戳+文件名命名,避免重复)
    const folderName = `${Date.now()}_${req.file.originalname.split('.')[0]}`;
    const folderId = await createFolder(folderName, auth);

    // 上传文件至新建文件夹
    const fileMetadata = {
      name: req.file.originalname,
      parents: [folderId]
    };
    const media = {
      mimeType: req.file.mimetype,
      body: fs.createReadStream(req.file.path),
    };
    const driveService = google.drive({ version: "v3", auth });
    const fileResponse = await driveService.files.create({
      requestBody: fileMetadata,
      media: media,
      fields: "id"
    });

    // 为文件夹设置权限
    await addFolderPermissions(folderId, emails, auth);

    // 删除本地临时文件
    deleteFile(req.file.path);

    // 返回文件夹ID和文件ID,供前端后续处理
    res.status(200).json({ 
      folderId, 
      fileId: fileResponse.data.id,
      authorizedEmails: emails
    });
  } catch (err) {
    console.error(err);
    res.status(500).send("Upload failed.");
  }
});

4. 前端JWT权限验证逻辑

前端需完成以下操作:

  • 解析JWT获取当前登录用户的邮箱
  • 方式一:直接对比上传时返回的authorizedEmails列表,匹配则展示文件和访问链接
  • 方式二:后端存储文件夹ID与授权邮箱的映射(如数据库),前端请求文件列表时携带JWT,后端解析邮箱后查询权限,返回可访问的文件资源

注意事项

  • 确保Google Cloud服务账号具备Google Drive API权限,且服务账号邮箱已被共享至Google Drive的根目录或父文件夹
  • 权限设置时,需验证前端传来的邮箱格式有效性,避免无效权限配置
  • 若需支持多文件上传,可将multer.single("file")改为multer.array("files", 10),并调整上传逻辑批量处理文件

内容的提问来源于stack exchange,提问作者gnar999

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 00:25:53