使用NodeJS服务账户调用Google Drive API时遇404文件未找到错误
问题:NodeJS中使用服务账户调用Google Drive API返回404权限错误
我在NodeJS中使用服务账户通过文件ID调用Google Drive API的GET接口,请求始终失败,返回如下404错误(根据官方错误文档,该错误实际代表权限不足):
{ "code": 404, "errors": [ { "message": "File not found: XXX.", "domain": "global", "reason": "notFound", "location": "fileId", "locationType": "parameter" } ] }
权限范围(Scope)
我测试过添加多个额外scope,但始终保留了https://www.googleapis.com/auth/drive:
const scopes = [ 'https://www.googleapis.com/auth/drive', 'https://www.googleapis.com/auth/drive.appdata', 'https://www.googleapis.com/auth/drive.file', 'https://www.googleapis.com/auth/drive.metadata', 'https://www.googleapis.com/auth/drive.metadata.readonly', 'https://www.googleapis.com/auth/drive.photos.readonly', 'https://www.googleapis.com/auth/drive.readonly', ];
服务账户(Service account)配置
- 按照常规流程创建了服务账户,参考过多个官方及第三方资源
- 已启用Google Drive API
- 在Google Admin控制台启用了Domain-wide Delegation,并配置了上述相同的scope(也测试过不启用该选项的情况)
源代码尝试
官方NodeJS快速入门采用OAuth2弹窗授权,不符合无用户交互的机器对机器访问需求,我尝试了多种实现方式:
使用google-auth-library包
const { auth } = require('google-auth-library'); const client = auth.fromJSON({ type: 'service_account', project_id: 'XXX', private_key_id: 'XXX', private_key: 'XXX', client_email: 'X@Y.iam.gserviceaccount.com', client_id: 'XXXX', auth_uri: 'https://accounts.google.com/o/oauth2/auth', token_uri: 'https://oauth2.googleapis.com/token', auth_provider_x509_cert_url: 'https://www.googleapis.com/oauth2/v1/certs', client_x509_cert_url: 'https://www.googleapis.com/robot/v1/metadata/x509/X%40Y.iam.gserviceaccount.com', }); const scopes = ['https://www.googleapis.com/auth/drive']; client.scopes = scopes; // 测试过supportsAllDrives设为true/false两种情况 const url = `https://www.googleapis.com/drive/v3/files/XXX?fields=name&supportsAllDrives=true`; client.request({ url }).then(console.log).catch(console.error);
使用ts-google-drive包
import { TsGoogleDrive } from 'ts-google-drive'; const tsGoogleDrive = new TsGoogleDrive({ credentials: { client_email: 'X@Y.iam.gserviceaccount.com', private_key: '', }, }); async function getSingleFile(fileId: string): Promise<void> { // 返回undefined表示请求出错 const file = await tsGoogleDrive.getFile(fileId); console.log('file', file); if (file) { const isFolder = file.isFolder; console.log('isFolder', isFolder); } } getSingleFile('XXX');
使用googleapis包
const { google } = require('googleapis'); const auth = new google.auth.GoogleAuth({ keyFile: 'service-account.json', // 文件路径正确 scopes: [...], // 使用上述相同的scope }); const drive = google.drive({ version: 'v3', auth }); const driveResponse = await drive.files.list({ fields: '*', }); const file = await drive.files.get({ fileId: 'XXX', fields: 'name', supportsAllDrives: true, }); console.log(file); // 此处报错!
使用googleapis搭配jwtClient
const google = require('googleapis'); const key = require('./service-account.json'); const scopes = [...]; // 使用上述相同的scope const jwtClient = new google.google.auth.JWT( key.client_email, null, key.private_key, scopes, null, ); jwtClient.authorize(async (authErr) => { if (authErr) { console.log(authErr); // 此处无错误 return; } const drive = google.google.drive({ version: 'v3', auth: jwtClient }); console.log('jwtClient.getCredentials()', jwtClient.getCredentials()); console.log('jwtClient.apiKey', jwtClient.apiKey); console.log('jwtClient.credentials', jwtClient.credentials); console.log('jwtClient.gtoken', jwtClient.gtoken); // 实际请求API时出错 const file = await drive.files.get({ fileId: 'XXX', fields: 'name', supportsAllDrives: true, }); console.log(file); });
./service-account.json文件结构:
{ "type": "service_account", "project_id": "X", "private_key_id": "XXXX", "client_email": "X@Y.iam.gserviceaccount.com", "client_id": "XXX", "auth_uri": "https://accounts.google.com/o/oauth2/auth", "token_uri": "https://oauth2.googleapis.com/token", "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/X%Y.iam.gserviceaccount.com" }
Google Drive资源权限
我需要访问公司内部Google Drive文件,在为服务账户分配权限时遇到问题:尝试向服务账户共享文件夹/驱动器失败。另外,即使是已单独共享给服务账户的文件(位于“与我共享”中)也无法访问,但公司Drive中的所有公开文件均可正常访问。
期望结果
实现无需用户交互,通过服务账户访问公司Drive中“与我共享”和“共享驱动器”内的文件。
内容的提问来源于stack exchange,提问作者michael
相关产品推荐
相关产品推荐

