web-dev-qa-db-fra.com

Autorisation de Google Drive à l'aide de JavaScript

J'essaie d'autoriser mon application à s'intégrer à Google Drive. La documentation de Google fournit des détails sur l'autorisation basée sur le serveur et des exemples de code pour diverses technologies de serveur .

Il y a aussi une bibliothèque API Google JavaScript , qui prend en charge l'autorisation. Dans la section des exemples du wiki il y a un extrait de code pour créer une configuration et appeler la fonction d'autorisation . J'ai modifié la portée pour être celle que je crois nécessaire pour le lecteur:

var config = {
    'client_id': 'my_client_ID',
    'scope': 'https://www.googleapis.com/auth/drive.file'
  };
  gapi.auth.authorize(config, function() {
    console.log(gapi.auth);
  });

La fonction de rappel n'est jamais appelée (oui, la bibliothèque de l'API Google est chargée corrigée) En regardant l'exemple Java Récupérer et utiliser OAuth 2.0 Informations d'identification, le secret client semble être un paramètre, si cela entre dans le config?

Quelqu'un a-t-il essayé cela dans JS, pour Drive ou d'autres API Google? Est-ce que quelqu'un connaît la meilleure voie pour déboguer un tel problème, c'est-à-dire dois-je simplement parcourir la bibliothèque et arrêter de pleurnicher?

Veuillez ne pas suggérer de faire l'autorisation côté serveur, notre application est entièrement côté client, je ne veux pas d'état sur le serveur (et je comprends les problèmes d'actualisation des jetons que cela entraînera). Je connais la configuration de l'API dans la console Google et je pense que le paramètre SDK du lecteur est correct.

41
David

Il est possible d'utiliser la bibliothèque client Javascript des API Google avec Drive, mais vous devez être conscient qu'il y a des problèmes.

Il existe actuellement 2 problèmes principaux, qui ont tous deux des contournements:

Autorisation

Tout d'abord, si vous examinez de près le fonctionnement de l'authentification Google Drive, vous vous rendrez compte qu'après qu'un utilisateur a installé votre application Drive et essaie d'ouvrir un fichier ou de créer un nouveau fichier avec votre application, Drive lance le OAuth 2.0 flux d'autorisation automatiquement et les paramètres d'authentification sont définis sur response_type = code et access_type = offline . Cela signifie essentiellement que les applications Drive sont actuellement obligées d'utiliser le flux côté serveur OAuth 2) qui ne sera d'aucune utilité pour le client Javascript. bibliothèque (qui utilise uniquement le flux côté client).

Le problème est le suivant: Drive initie un flux côté serveur OAuth 2.0, puis la bibliothèque client Javascript lance un flux côté client OAuth 2.0 flux.

Cela peut toujours fonctionner, il vous suffit d'utiliser du code côté serveur pour traiter le code d'autorisation renvoyé après le flux côté serveur Drive (vous devez l'échanger contre un jeton d'accès et un jeton d'actualisation). De cette façon, ce n'est que lors du premier flux que l'utilisateur sera invité à obtenir une autorisation. Après la première fois que vous échangez le code d'autorisation, la page d'authentification sera contournée automatiquement.

Des exemples côté serveur pour ce faire sont disponibles dans notre documentation .

Si vous ne traitez/échangez pas le code d'authentification sur le flux côté serveur, l'utilisateur sera invité à authentifier chaque fois qu'il essaie d'utiliser votre application à partir de Drive.

Gestion du contenu des fichiers

Le deuxième problème est que le téléchargement et l'accès au contenu réel du fichier Drive ne sont pas facilités par notre bibliothèque client Javascript. Vous pouvez toujours le faire mais vous devrez utiliser du code Javascript personnalisé.

Lecture du contenu du fichier

Lorsqu'une métadonnée de fichier/un objet fichier est récupéré, il contient un attribut downloadUrl qui pointe vers le contenu réel du fichier. Il est désormais possible de télécharger le fichier à l'aide d'une demande CORS et la manière la plus simple d'authentifier est d'utiliser le jeton d'accès OAuth 2 dans un paramètre d'URL. Ajoutez simplement &access_token=... dans downloadUrl et récupérez le fichier à l'aide de XHR ou en redirigeant l'utilisateur vers l'URL.

Téléchargement du contenu du fichier

UPDATE UPDATE: Les points de terminaison de téléchargement prennent désormais en charge CORS.

~~ MISE À JOUR: les points de terminaison de téléchargement, contrairement au reste de l'API Drive, ne prennent pas en charge CORS, vous devrez donc utiliser l'astuce ci-dessous pour l'instant: ~~

Le téléchargement d'un fichier est délicat car il n'est pas intégré à la bibliothèque client Javascript et vous ne pouvez pas le faire entièrement avec HTTP comme décrit dans cette réponse car nous n'autorisons pas les demandes interdomaines sur ces API points finaux. Vous devez donc profiter du proxy iframe utilisé par notre bibliothèque cliente Javascript et l'utiliser pour envoyer une demande multipartie construite au SDK Drive. Merci à @ Alain , nous avons un exemple de comment faire ci-dessous:

/**
 * Insert new file.
 *
 * @param {File} fileData File object to read data from.
 * @param {Function} callback Callback function to call when the request is complete.
 */
function insertFileData(fileData, callback) {
  const boundary = '-------314159265358979323846';
  const delimiter = "\r\n--" + boundary + "\r\n";
  const close_delim = "\r\n--" + boundary + "--";

  var reader = new FileReader();
  reader.readAsBinaryString(fileData);
  reader.onload = function(e) {
    var contentType = fileData.type || 'application/octet-stream';
    var metadata = {
      'title': fileData.fileName,
      'mimeType': contentType
    };

    var base64Data = btoa(reader.result);
    var multipartRequestBody =
        delimiter +
        'Content-Type: application/json\r\n\r\n' +
        JSON.stringify(metadata) +
        delimiter +
        'Content-Type: ' + contentType + '\r\n' +
        'Content-Transfer-Encoding: base64\r\n' +
        '\r\n' +
        base64Data +
        close_delim;

    var request = gapi.client.request({
        'path': '/upload/drive/v2/files',
        'method': 'POST',
        'params': {'uploadType': 'multipart'},
        'headers': {
          'Content-Type': 'multipart/mixed; boundary="' + boundary + '"'
        },
        'body': multipartRequestBody});
    if (!callback) {
      callback = function(file) {
        console.log(file)
      };
    }
    request.execute(callback);
  }
}

Pour améliorer tout cela, nous pourrions à l'avenir:

  • Laissez les développeurs choisir le flux OAuth 2.0 qu'ils souhaitent utiliser (côté serveur ou côté client) ou laissez le développeur gérer entièrement le flux OAuth).
  • Autoriser CORS sur le /upload/... points de terminaison
  • Autoriser CORS sur le exportLinks pour les gDocs natifs
  • Nous devrions faciliter le téléchargement de fichiers à l'aide de notre bibliothèque client Javascript.

Aucune promesse à ce stade cependant :)

56
Nicolas Garnier

Je l'ai fait. Voici mon code:

<!DOCTYPE html>
<html>
  <head>
    <meta charset='utf-8' />
    <style>
        p {         
            font-family: Tahoma;
        }
    </style>
  </head>
  <body>
    <!--Add a button for the user to click to initiate auth sequence -->
    <button id="authorize-button" style="visibility: hidden">Authorize</button>
    <script type="text/javascript">
      var clientId = '######';
      var apiKey = 'aaaaaaaaaaaaaaaaaaa';
      // To enter one or more authentication scopes, refer to the documentation for the API.
      var scopes = 'https://www.googleapis.com/auth/drive';

      // Use a button to handle authentication the first time.
      function handleClientLoad() {
        gapi.client.setApiKey(apiKey);
        window.setTimeout(checkAuth,1);
      }

      function checkAuth() {
        gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: true}, handleAuthResult);
      }

      function handleAuthResult(authResult) {
        var authorizeButton = document.getElementById('authorize-button');
        if (authResult && !authResult.error) {
          authorizeButton.style.visibility = 'hidden';
          makeApiCall();
        } else {
          authorizeButton.style.visibility = '';
          authorizeButton.onclick = handleAuthClick;
        }
      }

      function handleAuthClick(event) {
        gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: false}, handleAuthResult);
        return false;
      }

      // Load the API and make an API call.  Display the results on the screen.
      function makeApiCall() {
        gapi.client.load('drive', 'v2', function() {

          var request = gapi.client.drive.files.list ( {'maxResults': 5 } );

          request.execute(function(resp) {          
            for (i=0; i<resp.items.length; i++) {
                    var titulo = resp.items[i].title;
                    var fechaUpd = resp.items[i].modifiedDate;
                    var userUpd = resp.items[i].lastModifyingUserName;

                    var fileInfo = document.createElement('li');
                    fileInfo.appendChild(document.createTextNode('TITLE: ' + titulo + ' - LAST MODIF: ' + fechaUpd + ' - BY: ' + userUpd ));                
                    document.getElementById('content').appendChild(fileInfo);
            }
          });        
        });
      }
    </script>
    <script src="https://apis.google.com/js/client.js?onload=handleClientLoad"></script>    
    <p><b>These are 5 files from your GDrive :)</b></p>
    <div id="content"></div>
  </body>
</html>

Il suffit de changer:

  • var clientId = '######';
  • var apiKey = 'aaaaaaaaaaaaaaaaaaa';

à votre ID client et ApiKey depuis votre console API Google :)

Bien sûr, vous devez créer votre projet sur Google API Console, activer l'API Drive et activer l'authentification des comptes Google dans OAuth 2.0 (vraiment facile!)

PS: cela ne fonctionnera pas localement sur votre PC, cela fonctionnera sur certains hébergements, et vous devez fournir l'url de celui-ci sur la console du projet :)

12
InsaurraldeAP