Вызов API диска Google из бэкэнда nodejs с авторизацией из внешнего интерфейса

В настоящее время у меня есть приложение, которое требует от меня вызова api диска Google с клиента и сервера. Прямо сейчас я уже аутентифицировал пользователя во внешнем интерфейсе с помощью 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();
}

Теперь мне нужно позвонить в api из бэкэнда, написанного на NodesJS. Однако я хочу авторизовать эти вызовы, используя то, что у меня уже есть во внешнем интерфейсе. Токен аутентификации, который генерируется во внешнем интерфейсе для вызова, кажется только временным, поэтому я не думаю, что могу отправить его на бэкэнд для авторизации вызовов. Мне было интересно, знает ли кто-нибудь другой способ сделать это? Мне было интересно, знает ли кто-нибудь, как инициализировать API Google, чтобы использовать этот токен для совершения звонка.


person Victor Wang    schedule 17.08.2020    source источник
comment
@DaImTo вы хотите сказать, что если я использую этот токен обновления, чтобы делать все, я не смогу загружать данные с клиента? Мне пришлось бы отправить файл на сервер и загрузить оттуда? Нет ли возможности авторизовать запрос в клиенте с помощью токена обновления?   -  person Victor Wang    schedule 17.08.2020


Ответы (2)


Вы можете использовать паспорт в NodeJS для интеграции google auth 2.0, а затем использовать его во внешнем интерфейсе для аутентификации и входа пользователей. Как только пользователь войдет в систему, вы получите токен (от google auth) с другими данными пользователя (имя, адрес электронной почты и т. Д.). И затем вы можете сохранить это в своей базе данных (или в переменных сервера / json-файлах).

Теперь вы можете использовать сеанс для сохранения состояния пользователя или просто вызвать требуемый api с прикрепленным токеном (поддерживать его состояние во внешнем интерфейсе, React Hooks? Или просто файлы cookie тоже работают), и вы можете проверить, какой это пользователь.

Это своего рода грубое решение. Но я работал с ним аналогичным образом.

person Mahad Ansar    schedule 17.08.2020

Попробуйте ниже:

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);
        });
      });
person Rahul Beniwal    schedule 17.08.2020
comment
где ты найдешь код при авторизации в гугле? Когда я авторизуюсь с кодом, который я вставил выше в свой исходный вопрос, они никогда не отображают никаких кодов - person Victor Wang; 17.08.2020
comment
Они вернут код, когда Google перенаправит обратно на страницу после успешного входа в систему. Мы должны установить GOOGLE_REDIRECT_URI в приложении Google. - person Rahul Beniwal; 17.08.2020
comment
Проверьте этот URL developers.google.com/drive/api/v3/quickstart/nodejs. Процесс авторизации одинаков для всех приложений Google, таких как Google Диск, календари Google, формы Google и т. Д. После авторизации начинается основная работа по интеграции. Я надеюсь, что это помогает. - person Rahul Beniwal; 17.08.2020