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

Passport.js认证后调用GDrive API提示无有效凭证问题求助

报错核心原因

报错由两个代码逻辑问题直接导致:

  • fs.readFile是异步非阻塞IO操作,当前代码发起文件读取请求后,立刻同步执行listFiles(oauth2Client)和响应返回逻辑,此时文件读取尚未完成,oauth2Client.setCredentials方法根本没有执行,OAuth2客户端对象未携带任何有效凭证,触发无有效令牌的报错。
  • 凭证配置的字段取值错误:Passport.js完成Google OAuth授权后返回的令牌对象中,access_token、refresh_token为独立平级字段,代码中取data.token无法拿到正确的访问令牌;同时缺失refresh_token配置会导致访问令牌(默认有效期1小时)过期后直接鉴权失败。
修复方案

1. 修正异步执行顺序

将接口调用、响应返回逻辑移到文件读取完成的回调内,确保凭证设置完成后再调用Drive API,推荐使用fs的Promise版本配合async/await避免回调嵌套问题:

// 引入fs的Promise API
const fs = require('fs/promises');

app.get("/getinfo", async (req, resp) => {
  const oauth2Client = new google.auth.OAuth2(myClientID, myClientSecret, redirectURL);
  try {
    // 等待文件读取、解析、凭证配置全流程完成
    const fileContent = await fs.readFile("token.json", "utf-8");
    const tokenData = JSON.parse(fileContent);
    oauth2Client.setCredentials(tokenData);
    // 凭证配置完成后再调用文件列表接口
    const files = await listFiles(oauth2Client);
    resp.send({
      message: "获取Drive文件列表成功",
      data: files
    });
  } catch (err) {
    resp.status(500).send(`接口调用失败: ${err.message}`);
  }
});

2. 调整listFiles方法适配异步流程

将原有回调写法改为Promise形式,配合async/await保证时序正确:

async function listFiles(auth) {
  const drive = google.drive({version: 'v3', auth});
  const res = await drive.files.list({
    pageSize: 10,
    fields: 'nextPageToken, files(id, name)',
  });
  const files = res.data.files;
  if (files.length) {
    console.log('Drive文件列表:');
    files.forEach(file => console.log(`${file.name} (${file.id})`));
    return files;
  }
  console.log('账号下未找到文件');
  return [];
}

3. 修正token存储逻辑

Passport.js的Google授权策略返回的完整令牌对象可以直接传入setCredentials方法,不需要额外包装,存储token.json时直接保存完整令牌结构即可,不要自定义token字段包装access_token,正确的token结构参考:

{
  "access_token": "ya29.xxx实际访问令牌xxx",
  "refresh_token": "1//0gxxx实际刷新令牌xxx",
  "scope": "https://www.googleapis.com/auth/drive.readonly",
  "token_type": "Bearer",
  "expiry_date": 172xxxxxxxxx
}

注意:如果授权后拿不到refresh_token,需要在Passport的Google策略配置中添加两个参数:

passport.use(new GoogleStrategy({
    clientID: myClientID,
    clientSecret: myClientSecret,
    callbackURL: redirectURL,
    accessType: 'offline', // 申请离线访问权限,才会返回refresh_token
    prompt: 'consent' // 强制弹出授权页,解决历史授权未返回refresh_token的问题
  },
  async (accessToken, refreshToken, params, profile, done) => {
    // 直接将完整令牌对象存入token.json即可
    const fullToken = { access_token: accessToken, refresh_token: refreshToken, ...params };
    await fs.writeFile("token.json", JSON.stringify(fullToken));
    // 后续用户信息存储、登录逻辑
  }
));

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.03 04:09:41