You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何借助Passport Google认证实现用户通过Node.js服务器调用YouTube API上传视频?

嘿,这个问题我之前刚好折腾过,其实核心是要从Passport的Google OAuth流程里拿到用户的刷新令牌,而不是用服务账号的JSON凭证。下面是具体的步骤和代码示例,应该能帮到你:

核心思路

Google的YouTube Data API需要的是用户授权的OAuth 2.0凭证(而非服务账号的密钥文件),Passport的Google策略刚好可以帮我们完成用户授权流程,拿到访问令牌和刷新令牌——之后就用这些用户专属的凭证来调用上传API就行。

具体实现步骤

1. 配置Passport Google策略,请求正确权限

首先得在Passport的Google策略里,指定YouTube上传所需的权限范围,还要确保能获取到刷新令牌(这是长期调用API的关键,因为访问令牌1小时就会过期)。

关键配置点:

  • 添加scope: ['https://www.googleapis.com/auth/youtube.upload']来请求上传权限
  • 设置accessType: 'offline'prompt: 'consent',确保能拿到refreshToken

示例代码:

const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;

passport.use(new GoogleStrategy({
    clientID: process.env.GOOGLE_CLIENT_ID,
    clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    callbackURL: '/auth/google/callback',
    accessType: 'offline', // 必须:获取长期有效的刷新令牌
    prompt: 'consent' // 确保授权时返回refreshToken(即使用户之前授权过)
  },
  function(accessToken, refreshToken, profile, done) {
    // 这里把refreshToken、accessToken和用户信息绑定,存到数据库
    // 示例:用用户的Google ID查找或创建用户记录
    User.findOneAndUpdate(
      { googleId: profile.id },
      { 
        accessToken, 
        refreshToken, 
        googleId: profile.id,
        displayName: profile.displayName
      },
      { upsert: true, new: true },
      (err, user) => done(err, user)
    );
  }
));

2. 处理授权回调,保存用户凭证

当用户在Google授权页面确认后,会跳转到你设置的callbackURL,这里要完成Passport的认证流程,并且把拿到的refreshTokenaccessToken持久化到数据库——这一步非常重要,没有刷新令牌就没法长期调用API。

示例回调路由:

app.get('/auth/google', passport.authenticate('google'));

app.get('/auth/google/callback', 
  passport.authenticate('google', { failureRedirect: '/login' }),
  function(req, res) {
    // 授权成功,跳转到用户的个人页面或上传页面
    res.redirect('/upload');
  }
);

3. 使用用户凭证调用YouTube上传API

当用户需要上传视频时,从数据库取出该用户的refreshToken,用Google官方的googleapis库创建OAuth客户端,然后调用上传接口。

注意:googleapis库会自动检测访问令牌是否过期,如果过期会用刷新令牌自动获取新的访问令牌,非常方便。

示例上传函数:

const { google } = require('googleapis');
const fs = require('fs');
const User = require('./models/User'); // 你的用户模型

async function uploadVideo(userId, videoData) {
  // 从数据库获取用户的refreshToken
  const user = await User.findById(userId);
  if (!user.refreshToken) {
    throw new Error('用户未授权YouTube上传权限,请先完成Google授权');
  }

  // 创建OAuth2客户端
  const oauth2Client = new google.auth.OAuth2(
    process.env.GOOGLE_CLIENT_ID,
    process.env.GOOGLE_CLIENT_SECRET
  );
  // 设置客户端凭证
  oauth2Client.setCredentials({
    refresh_token: user.refreshToken,
    access_token: user.accessToken // 可选:如果没过期可以直接用,库会自动刷新
  });

  // 监听令牌刷新事件,更新数据库里的accessToken
  oauth2Client.on('tokens', (tokens) => {
    if (tokens.access_token) {
      User.findByIdAndUpdate(userId, { accessToken: tokens.access_token })
        .catch(err => console.error('更新访问令牌失败:', err));
    }
  });

  // 创建YouTube API客户端
  const youtube = google.youtube({
    version: 'v3',
    auth: oauth2Client
  });

  // 执行视频上传
  const uploadResponse = await youtube.videos.insert({
    part: 'snippet,status', // 必须指定要设置的字段部分
    requestBody: {
      snippet: {
        title: videoData.title,
        description: videoData.description,
        tags: videoData.tags || []
      },
      status: {
        privacyStatus: videoData.privacyStatus || 'private' // 可选:public/private/unlisted
      }
    },
    media: {
      body: fs.createReadStream(videoData.filePath) // 本地视频文件的路径
    }
  });

  return {
    videoId: uploadResponse.data.id,
    url: `https://www.youtube.com/watch?v=${uploadResponse.data.id}`
  };
}
关键注意事项
  • 权限范围不能错:必须请求https://www.googleapis.com/auth/youtube.upload,否则会提示权限不足
  • 刷新令牌的获取:只有首次授权或者设置prompt: 'consent'时才会返回refreshToken,所以一定要在第一次拿到时就保存到数据库,避免丢失
  • 安全问题:绝对不能把refreshToken暴露给前端,所有API调用都要在服务端完成,防止凭证泄露被滥用
  • 令牌刷新googleapis库会自动处理令牌过期,但最好监听tokens事件,把新的accessToken更新到数据库,提升后续调用效率

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

火山引擎 最新活动