如何借助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的认证流程,并且把拿到的refreshToken和accessToken持久化到数据库——这一步非常重要,没有刷新令牌就没法长期调用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




