Skip to content

搞英语 → 看世界

翻译英文优质信息和名人推特

Menu
  • 首页
  • 作者列表
  • 独立博客
  • 专业媒体
  • 名人推特
  • 邮件列表
  • 关于本站
Menu

如何使用 Google OAuth 2.0 通过 Refresh Token 访问 Google API

Posted on 2022-04-23

让我们构建一个使用 Google OAuth 2.0 访问 Google API 的简单 Web 应用程序。用户可以使用他们的 Google 帐户登录并授权应用程序访问他们的 Google Drive 或任何其他 Google 服务。

当用户登录时,Google 会将用户重定向到 Google OAuth 2.0 授权页面。要求用户授予对应用程序的访问权限。然后,应用程序将授权代码交换为访问令牌和刷新令牌。访问令牌将在一小时后过期,但刷新令牌将无限期有效(除非用户手动撤销)。

因此,我们会将刷新令牌存储在 Cloud Firestore 中,并在应用程序需要代表用户访问 Google API 时使用它来生成新的访问令牌。

我们没有使用带有 Firebase 身份验证的 Google 登录,因为它不提供在无人值守的情况下运行后台 API 任务所需的刷新令牌。

第 1 步:创建 Google OAuth 2.0 客户端

如本分步指南中所述,在您的 Google Cloud 项目中创建一个新的 OAuth 2.0 客户端。

在您的 Google Cloud Console 中,转到APIs & Services部分,单击Credentials ,然后单击Create credentials > OAuth Client Id以创建新的客户端 ID。

Google OAuth Sign-in

在开发过程中,您可以将https://localhost:5001/oauthCallback作为重定向 URI,因为默认情况下,Firebase 模拟器将在本地端口 5001 上运行 Web 应用程序。

记下 Google 提供的客户端 ID 和客户端密码。

第 2 步:初始化 Firebase 函数

打开你的终端,创建一个新的项目目录并初始化 Firebase 项目。

 $ mkdir oauth2-application $ cd oauth2-application $ npx firebase init functions $ npm install googleapis

您可以选择Use an existing Firebase project选项,然后选择具有该功能的 Google Cloud 项目。切换到functions目录。

步骤 3.初始化 Firebase 环境变量

创建一个新的.env文件并添加以下环境变量:

 CLIENT_ID = < your client ID > CLIENT_SECRET = < your client secret > REDIRECT_URI = < your redirect URI >

步骤 4. 生成授权 URL

我们将创建一个函数来生成授权 URL,以便用户使用其 Google 帐户登录。除了drive范围之外,我们的应用程序还请求userinfo.email范围以获取用户的电子邮件地址。

 const functions = require ( 'firebase-functions' ) ; const { google } = require ( 'googleapis' ) ; exports . googleLogin = functions . https . onRequest ( ( request , response ) => { const SCOPES = [ 'https://www.googleapis.com/auth/userinfo.email' , 'https://www.googleapis.com/auth/drive.metadata.readonly' , ] ; const oAuth2Client = new google . auth . OAuth2 ( process . env . CLIENT_ID , process . env . CLIENT_SECRET , process . env . REDIRECT_URI ) ; const authUrl = oAuth2Client . generateAuthUrl ( { access_type : 'offline' , scope : SCOPES , prompt : 'consent' , login_hint : request . query . email_address || '' , } ) ; response . set ( 'Cache-Control' , 'private, max-age=0, s-maxage=0' ) ; response . redirect ( authUrl ) ; } ) ;

我们将access_type设置为offline以获取刷新令牌。 consent设置为prompt强制用户同意该应用程序。如果用户登录到多个 Google 帐户,我们还将login_hint设置为用户的电子邮件地址。

步骤 5. 存储刷新令牌

用户登录后,Google 会将用户重定向到重定向 URI。重定向 URI 包含我们需要交换访问令牌和刷新令牌以存储在数据库中的授权代码。

 const functions = require ( 'firebase-functions' ) ; const admin = require ( 'firebase-admin' ) ; const { google } = require ( 'googleapis' ) ; admin . initializeApp ( ) ; exports . oAuthCallback = functions . https . onRequest ( async ( request , response ) => { const { query : { error , code } = { } } = request ; // User may deny access to the application. if ( error ) { response . status ( 500 ) . send ( error ) ; return ; } const oAuth2Client = new google . auth . OAuth2 ( process . env . CLIENT_ID , process . env . CLIENT_SECRET , process . env . REDIRECT_URI ) ; // Exchange the authorization code for an access token. const { tokens } = await oAuth2Client . getToken ( code ) ; oAuth2Client . setCredentials ( tokens ) ; const oauth2 = google . oauth2 ( { auth : oAuth2Client , version : 'v2' , } ) ; // Get the user's email address and Google user ID const { data } = await oauth2 . userinfo . get ( ) ; const { id , email } = data ; const { refresh_token } = tokens ; // Store the refresh token in the Firestore database. // Set merge: true to not overwrite any other data in the same document await admin . firestore ( ) . collection ( 'users' ) . doc ( id ) . set ( { id , email , refresh_token } , { merge : true } ) ; response . set ( 'Cache-Control' , 'private, max-age=0, s-maxage=0' ) ; response . send ( ` User ${ email } is authorized! ${ id } ` ) ; } ) ;

以下是文档在 Firestore NoSQL 数据库中的存储方式:

Firestore Access Token

第 6 步:访问 Google API

现在我们有了刷新令牌,我们可以使用它来生成新的访问令牌并访问 Google API。在我们的示例中,drive 函数将返回授权用户的 Google Drive 中最近的 5 个文件。

 const functions = require ( 'firebase-functions' ) ; const admin = require ( 'firebase-admin' ) ; const { google } = require ( 'googleapis' ) ; admin . initializeApp ( ) ; exports . drive = functions . https . onRequest ( async ( request , response ) => { const { user_id = '' } = request . query ; const user = await admin . firestore ( ) . collection ( 'users' ) . doc ( user_id ) . get ( ) ; if ( ! user . exists ) { response . status ( 404 ) . send ( ` User ${ user_id } not found ` ) ; return ; } const { refresh_token } = user . data ( ) ; const oAuth2Client = new google . auth . OAuth2 ( process . env . CLIENT_ID , process . env . CLIENT_SECRET , process . env . REDIRECT_URI ) ; oAuth2Client . setCredentials ( { refresh_token } ) ; const googleDrive = google . drive ( { version : 'v3' , auth : oAuth2Client } ) ; const { data : { files = [ ] } = { } } = await googleDrive . files . list ( { pageSize : 5 , fields : 'files(id, name)' , } ) ; response . status ( 200 ) . send ( { files } ) ; } ) ;

第 7 步:创建 Firebase 云函数

您可以运行以下命令在本地测试功能:

 firebase emulators:start --only functions

当您准备好将函数部署到 Firebase 项目时,您可以运行以下命令:

 firebase deploy --only functions

原文: https://www.labnol.org/google-oauth-refresh-token-220423

本站文章系自动翻译,站长会周期检查,如果有不当内容,请点此留言,非常感谢。
  • Abhinav
  • Abigail Pain
  • Adam Fortuna
  • Alberto Gallego
  • Alex Wlchan
  • Answer.AI
  • Arne Bahlo
  • Ben Carlson
  • Ben Kuhn
  • Bert Hubert
  • Bits about Money
  • Brian Krebs
  • ByteByteGo
  • Chip Huyen
  • Chips and Cheese
  • Christopher Butler
  • Colin Percival
  • Cool Infographics
  • Dan Sinker
  • David Walsh
  • Dmitry Dolzhenko
  • Dustin Curtis
  • Elad Gil
  • Ellie Huxtable
  • Ethan Marcotte
  • Exponential View
  • FAIL Blog
  • Founder Weekly
  • Geoffrey Huntley
  • Geoffrey Litt
  • Greg Mankiw
  • Henrique Dias
  • Hypercritical
  • IEEE Spectrum
  • Investment Talk
  • Jaz
  • Jeff Geerling
  • Jonas Hietala
  • Josh Comeau
  • Lenny Rachitsky
  • Liz Danzico
  • Lou Plummer
  • Luke Wroblewski
  • Matt Baer
  • Matt Stoller
  • Matthias Endler
  • Mert Bulan
  • Mostly metrics
  • News Letter
  • NextDraft
  • Non_Interactive
  • Not Boring
  • One Useful Thing
  • Phil Eaton
  • Product Market Fit
  • Readwise
  • ReedyBear
  • Robert Heaton
  • Ruben Schade
  • Sage Economics
  • Sam Altman
  • Sam Rose
  • selfh.st
  • Shtetl-Optimized
  • Simon schreibt
  • Slashdot
  • Small Good Things
  • Taylor Troesh
  • Telegram Blog
  • The Macro Compass
  • The Pomp Letter
  • thesephist
  • Thinking Deep & Wide
  • Tim Kellogg
  • Understanding AI
  • 英文媒体
  • 英文推特
  • 英文独立博客
©2025 搞英语 → 看世界 | Design: Newspaperly WordPress Theme