NextJS中使用服务账户调用Google Drive API遇权限不足问题
Google Drive API 权限不足问题排查
问题背景
- 个人Google Drive文件夹已共享给GCP创建的服务账户
creds.json文件包含服务账户的正确密钥
实现代码
const credsDir = path.join(process.cwd(), '.'); const credsFile = fs.readFileSync(credsDir + '/creds.json', 'utf-8'); const credsJson = JSON.parse(credsFile); const authClient = new google.auth.GoogleAuth({ credsJson, scopes: "https://www.googleapis.com/auth/drive" }); const drive = google.drive({ version: 'v3', auth: authClient }); const response = await drive.files.list() // 也曾尝试 drive.files.list({ driveId: xxxxxxxxxxxxxxxxx }) // 也曾尝试除列出文件外的其他操作
错误信息
error - GaxiosError: Insufficient Permission at Gaxios._request [...] { response: { config: { url: 'https://www.googleapis.com/drive/v3/files', method: 'GET', userAgentDirectives: [Array], paramsSerializer: [Function (anonymous)], headers: [Object], params: {}, validateStatus: [Function (anonymous)], retry: true, responseType: 'json', retryConfig: [Object] }, data: { error: [Object] }, headers: { 'alt-svc': 'h3=":443"; ma=2592000,h3-29=":443"; ma=2592000', 'cache-control': 'private', connection: 'close', 'content-encoding': 'gzip', 'content-type': 'application/json; charset=UTF-8', date: 'Fri, 07 Apr 2023 09:40:28 GMT', server: 'ESF', 'transfer-encoding': 'chunked', 'www-authenticate': 'Bearer realm="https://accounts.google.com/", error="insufficient_scope", scope="https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/drive.appdata https://www.googleapis.com/auth/drive.appfolder https://www.googleapis.com/auth/drive.file https://www.googleapis.com/auth/drive.resource https://www.googleapis.com/auth/drive.metadata https://www.googleapis.com/auth/drive.metadata.readonly https://www.googleapis.com/auth/drive.readonly.metadata https://www.googleapis.com/auth/drive.photos.readonly https://www.googleapis.com/auth/drive.readonly"', 'x-content-type-options': 'nosniff', 'x-frame-options': 'SAMEORIGIN', 'x-xss-protection': '0' }, status: 403, statusText: 'Forbidden', request: { responseURL: 'https://www.googleapis.com/drive/v3/files' } }, config: { url: 'https://www.googleapis.com/drive/v3/files', method: 'GET', userAgentDirectives: [ [Object] ], paramsSerializer: [Function (anonymous)], headers: { 'x-goog-api-client': 'gdcl/6.0.4 gl-node/17.9.0 auth/8.7.0', 'Accept-Encoding': 'gzip', 'User-Agent': 'google-api-nodejs-client/6.0.4 (gzip)', Authorization: '<some bearer token>', Accept: 'application/json' }, params: {}, validateStatus: [Function (anonymous)], retry: true, responseType: 'json', retryConfig: { currentRetryAttempt: 0, retry: 3, httpMethodsToRetry: [Array], noResponseRetries: 2, statusCodesToRetry: [Array] } }, code: 403, errors: [ { message: 'Insufficient Permission', domain: 'global', reason: 'insufficientPermissions' } ], page: '/api/gdrive-images' }
可能遗漏的配置项
1. 认证参数名错误
Google Auth客户端的初始化参数应为credentials,而非自定义的credsJson,修正后代码:
const authClient = new google.auth.GoogleAuth({ credentials: credsJson, scopes: "https://www.googleapis.com/auth/drive" });
2. 文件夹共享权限配置
- 确认共享对象是服务账户的完整邮箱(格式:
xxx@xxx.iam.gserviceaccount.com),而非个人邮箱或其他账户 - 给服务账户的权限至少为查看者,若需修改文件则设为编辑者
- 避免使用“域内用户”权限,服务账户不属于个人Google域
3. Google Drive API未启用
登录GCP控制台,检查当前项目是否已启用Google Drive API,未启用的话即使密钥正确也会返回权限错误
4. 文件列表请求未指定目标文件夹
默认drive.files.list()会列出服务账户自身Drive的文件,需通过q参数过滤共享文件夹:
const response = await drive.files.list({ q: "'你的共享文件夹ID' in parents", fields: "files(id, name)" // 按需指定返回字段 });
注意:driveId参数用于共享驱动器(Team Drive),个人文件夹共享无需使用
5. 令牌缓存残留
若之前使用过低权限范围,可能存在缓存令牌。可删除本地缓存(如~/.config/gcloud/下的相关文件),或重启服务强制重新获取令牌
内容的提问来源于stack exchange,提问作者Georgian
相关产品推荐
相关产品推荐

