【问题标题】:Calling google drive api from nodejs backend with authorisation from front end使用前端授权从nodejs后端调用google drive api
【发布时间】:2020-08-18 00:35:20
【问题描述】:

我目前有一个应用程序需要我从客户端和服务器调用 google drive api。现在,我已经在前端使用 auth 2.0 对用户进行了身份验证,我可以正常上传文件了。

本节的大部分代码,我从文档和各种博客文章中搜集而来。

async function uploadDocGoogle() {
    // get file
    const fileChooser = document.getElementById('config-file-upload');
    const file = fileChooser.files[0];
    
    console.log("file", file);
    
    const fileMetaData = {
        'name': file.name,
        'mimeType': file.type
    };

    var accessToken = gapi.auth.getToken().access_token; // Here gapi is used for retrieving the access token.
    await setGoogleAPIToken(accessToken);
    console.log(accessToken);

    var form = new FormData();
    form.append('metadata', new Blob([JSON.stringify(fileMetaData)], {type: 'application/json'}));
    form.append('file', file);

    var xhr = new XMLHttpRequest();
    xhr.open('post', 'https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart&fields=id');
    xhr.setRequestHeader('Authorization', 'Bearer ' + accessToken);
    xhr.responseType = 'json';
    xhr.onload = () => {
        console.log(xhr.response.id); // Retrieve uploaded file ID.
        console.log(xhr);
    };
    xhr.send(form);
}

var SCOPES = 'https://www.googleapis.com/auth/drive';

var authorizeButton = document.getElementById('config-google-test');

/**
*  On load, called to load the auth2 library and API client library.
*/
function handleClientLoad() {
gapi.load('client:auth2', initClient);
}

/**
*  Initializes the API client library and sets up sign-in state
*  listeners.
*/
function initClient() {
gapi.client.init({
  apiKey: API_KEY,
  clientId: CLIENT_ID,
  discoveryDocs: DISCOVERY_DOCS,
  scope: SCOPES
}).then(function () {
  // Listen for sign-in state changes.
  gapi.auth2.getAuthInstance().isSignedIn.listen(updateSigninStatus);

  // Handle the initial sign-in state.
  updateSigninStatus(gapi.auth2.getAuthInstance().isSignedIn.get());
  //authorizeButton.onclick = handleAuthClick;
}, function(error) {
  appendPre(JSON.stringify(error, null, 2));
});
}

/**
*  Called when the signed in status changes, to update the UI
*  appropriately. After a sign-in, the API is called.
*/
function updateSigninStatus(isSignedIn) {
if (isSignedIn) {
    console.log("Logged In");
} else {
    console.log("Logged Out");
}
}

/**
*  Sign in the user upon button click.
*/
function handleAuthClick(event) {
gapi.auth2.getAuthInstance().signIn();
}

/**
*  Sign out the user upon button click.
*/
function handleSignoutClick(event) {
gapi.auth2.getAuthInstance().signOut();
}

现在我需要从用 NodesJS 编写的后端调用 api。但是,我想使用我已经从前端获得的内容来授权这些调用。在前端为调用生成的身份验证令牌似乎只是临时的,所以我认为我不能将其发送到后端来授权调用。我想知道是否有人知道另一种方法?我想知道是否有人也知道如何初始化 google api 以使用该令牌进行调用。

【问题讨论】:

  • @DaImTo 你是说如果我使用这个刷新令牌来做所有事情,我将无法从客户端上传?我必须将文件发送到服务器并从那里上传?有没有办法使用刷新令牌在客户端授权请求?

标签: node.js oauth-2.0 google-drive-api google-oauth google-api-nodejs-client


【解决方案1】:

您可以在 NodeJS 中使用 passport 来集成 google auth 2.0,然后在前端使用它来验证和登录用户。用户登录后,您将获得带有其他用户数据(姓名、电子邮件等)的令牌(来自 google auth)。然后您可以将其存储在您的数据库(或服务器变量/json 文件)中。

现在,您可以使用 session 来保存用户状态,或者简单地调用所需的 api 并附加令牌(在前端保持其状态,React Hooks?或者只是 cookie 也可以工作),您可以验证它是哪个用户。

这是一种粗略的解决方案。但我以类似的方式使用它。

【讨论】:

    【解决方案2】:

    试试下面:

    const fs = require('fs');
    const readline = require('readline');
    const {google} = require('googleapis');
    
    const SCOPES = ['https://www.googleapis.com/auth/drive.metadata.readonly'];
    
    const TOKEN_PATH = 'token.json';// You can save token in dB as well
    
    fs.readFile('credentials.json', (err, content) => {
      if (err) return console.log('Error loading client secret file:', err);
      // Authorize a client with credentials, then call the Google Drive API.
      authorize(JSON.parse(content), listFiles);
    });
    
    function authorize(credentials, callback) {
      const {client_secret, client_id, redirect_uris} = credentials.installed;
      const oAuth2Client = new google.auth.OAuth2(
          client_id, client_secret, redirect_uris[0]);
    
      // Check if we have previously stored a token.
      fs.readFile(TOKEN_PATH, (err, token) => {
        if (err) return getAccessToken(oAuth2Client, callback);
        oAuth2Client.setCredentials(JSON.parse(token));
        callback(oAuth2Client);
      });
    }
    
    function getAccessToken(oAuth2Client, callback) {
      const authUrl = oAuth2Client.generateAuthUrl({
        access_type: 'offline',
        scope: SCOPES,
      });
      console.log('Authorize this app by visiting this url:', authUrl);
      const rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout,
      });
      rl.question('Enter the code from that page here: ', (code) => {
        rl.close();
        oAuth2Client.getToken(code, (err, token) => {
          if (err) return console.error('Error retrieving access token', err);
          oAuth2Client.setCredentials(token);
          // Store the token to disk for later program executions
          fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
            if (err) return console.error(err);
            console.log('Token stored to', TOKEN_PATH);
          });
          callback(oAuth2Client);
        });
      });
    }
    
    function listFiles(auth) {
      const drive = google.drive({version: 'v3', auth});
      drive.files.list({
        pageSize: 10,
        fields: 'nextPageToken, files(id, name)',
      }, (err, res) => {
        if (err) return console.log('The API returned an error: ' + err);
        const files = res.data.files;
        if (files.length) {
          console.log('Files:');
          files.map((file) => {
            console.log(`${file.name} (${file.id})`);
          });
        } else {
          console.log('No files found.');
        }
      });
    }
    

    如果你想使用前端,'getAccessToken' 可以简化。什么时候你会得到一个谷歌授权的账户。 Google 会返回一个代码给您。在此函数中使用该代码。这将实现您的目标。

    rl.question('Enter the code from that page here: ', (code) => {
            rl.close();
            oAuth2Client.getToken(code, (err, token) => {
              if (err) return console.error('Error retrieving access token', err);
              oAuth2Client.setCredentials(token);
              // Store the token to disk for later program executions
              fs.writeFile(TOKEN_PATH, JSON.stringify(token), (err) => {
                if (err) return console.error(err);
                console.log('Token stored to', TOKEN_PATH);
              });
              callback(oAuth2Client);
            });
          });
    

    【讨论】:

    • 你在google授权时在哪里找到代码?当我使用我在原始问题中粘贴的代码进行授权时,它们不会显示任何代码
    • 成功登录后,当谷歌重定向回页面时,他们将返回代码。我们必须在谷歌应用程序中设置 GOOGLE_REDIRECT_URI。
    • 检查此网址 developers.google.com/drive/api/v3/quickstart/nodejs 。每个谷歌应用程序的授权过程都是相同的,如谷歌驱动器、谷歌日历、谷歌表单等。授权后主要集成工作开始。我希望它有所帮助。
    猜你喜欢
    • 2018-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-18
    • 2013-09-06
    • 2015-12-26
    相关资源
    最近更新 更多