使用前端的授权从Node.js后端调用Google Drive API

问题描述

我目前有一个应用程序,要求我从客户端和服务器调用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。但是,我想使用前端已经拥有的功能来授权这些调用。在前端为呼叫生成的auth令牌似乎只是临时的,因此我认为我无法将其发送到后端以授权呼叫。我想知道是否有人知道另一种方法?我想知道是否有人还知道如何初始化Google Api以使用该令牌进行呼叫。

解决方法

尝试以下方法:

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,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,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)',},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时。 Google会退还给您一个验证码。在此函数中使用该代码。这将实现您的目标。

rl.question('Enter the code from that page here: ',(code) => {
        rl.close();
        oAuth2Client.getToken(code,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,(err) => {
            if (err) return console.error(err);
            console.log('Token stored to',TOKEN_PATH);
          });
          callback(oAuth2Client);
        });
      });
,

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

现在,您可以使用会话来保留用户状态,或者简单地调用带有附加令牌的必需的api(在前端,React Hooks中保留其状态?还是cookie可以正常工作),并且可以验证它是哪个用户。 / p>

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