1
votes

Comptes de service / API Google - J'obtiens toujours l'erreur: Accès non accordé ou expiré. (ligne 454, fichier «Service»)

J'ai cherché pendant des heures une réponse à cette question, alors soyez indulgents avec moi!

J'utilise Apps Script pour me connecter à l'API Google Drive. J'ai créé un compte de service dans la console et collecté les informations d'identification pertinentes. J'ai le code suivant:

function test()
{


function getOAuthService(user) {
var JSON = {
    "private_key": "-----BEGIN PRIVATE KEY-----\nMY KEY HERE\n",
    "client_email": "clientemail@clientemail.iam.gserviceaccount.com",
    "client_id": "11111111111111",
    "user_email": "myemail@myemail.com"
};
    return OAuth2.createService("Service Account")
        .setTokenUrl('https://accounts.google.com/o/oauth2/token')
        .setPrivateKey(JSON.private_key)
        .setIssuer(JSON.client_email)
        .setSubject(JSON.user_email)
        .setPropertyStore(PropertiesService.getScriptProperties())
        .setParam('access_type', 'offline')
        .setScope('https://www.googleapis.com/auth/drive');
}

function getUserFiles() {
    var service = getOAuthService();
    service.reset();

        var url = 'https://www.googleapis.com/drive/v2/files?pageSize=1';
        var response = UrlFetchApp.fetch(url, {
            headers: {
                Authorization: 'Bearer ' + service.getAccessToken()
            }, muteHttpExceptions: true
        });
        Logger.log(response.getContentText());
    
}

function reset() {
    var service = getOAuthService();
    service.reset();
}

getUserFiles()
}

J'ai également ajouté la bibliothèque OAuth2 dans le script.

Chaque fois que j'exécute cela, je rencontre l'erreur suivante: Erreur: accès non accordé ou expiré. (ligne 454, fichier «Service»)

Est-ce que quelqu'un a des idées?

Merci!


3 commentaires

avez-vous une "ligne 454"?


Je pense que l'op fait référence à cette ligne var response = UrlFetchApp.fetch(url, { headers: {Authorization: 'Bearer ' + service.getAccessToken()}, muteHttpExceptions: true });


Je n'ai pas de ligne 454, je suppose que cela fait partie de l'API. Aucune suggestion?


3 Réponses :


1
votes

Que diriez-vous de la modification suivante?

De:

return OAuth2.createService("Service Account")
    .setTokenUrl('https://accounts.google.com/o/oauth2/token')
    .setPrivateKey(JSON.private_key)
    .setIssuer(JSON.client_email)
    // .setSubject(JSON.user_email)  // <--- Removed
    .setPropertyStore(PropertiesService.getScriptProperties())
    .setParam('access_type', 'offline')
    .setScope('https://www.googleapis.com/auth/drive');

À:

return OAuth2.createService("Service Account")
    .setTokenUrl('https://accounts.google.com/o/oauth2/token')
    .setPrivateKey(JSON.private_key)
    .setIssuer(JSON.client_email)
    .setSubject(JSON.user_email)
    .setPropertyStore(PropertiesService.getScriptProperties())
    .setParam('access_type', 'offline')
    .setScope('https://www.googleapis.com/auth/drive');

Remarque:

  • À titre d'information supplémentaire, lorsque la liste des fichiers est récupérée par le compte de service, le Drive est différent de votre Google Drive de votre compte Google. Veuillez faire attention à cela. Si vous souhaitez récupérer la liste des fichiers de votre Google Drive, par exemple, lorsqu'un dossier de votre Google Drive est partagé avec l'adresse e-mail du compte de service, la liste des fichiers du dossier peut être récupérée par le compte de service.

  • D'après les commentaires d'Iamblichus. Réf et Réf

    • Le code d'origine aurait été correct si le compte de service avait reçu une autorité à l'échelle du domaine et que l'OP voulait utiliser le SA pour usurper l'identité d'un autre utilisateur dans le domaine (cela se fait via .setSubject , mais ne fonctionnera pas si domaine- la délégation large n’est pas définie). Mais comme l'OP souhaitait accéder au Drive du compte de service et ne pas se faire passer pour un autre compte, il n'y avait aucune raison d'utiliser .setSubject .

Référence:


3 commentaires

Merci pour votre réponse. Bien que l'OP n'ait pas clarifié sa situation sur la question, je pense qu'il serait approprié de clarifier un peu plus cela, pour d'autres personnes confrontées à ce même problème: le code d'origine aurait été correct si le compte de service avait obtenu un domaine -wide et l'OP souhaitaient utiliser la SA pour se faire passer pour un autre utilisateur du domaine (cela se fait via .setSubject , mais ne fonctionnera pas si la délégation à l'échelle du domaine n'est pas définie).


Mais comme l'OP souhaitait accéder au Drive du compte de service et ne pas se faire passer pour un autre compte, il n'y avait aucune raison d'utiliser .setSubject .


@Iamblichus Merci pour votre soutien constant. Je pourrais ajouter vos informations supplémentaires à la section Node. Je pense également que ce sera utile pour les autres utilisateurs. Merci beaucoup.



0
votes

Vous pouvez utiliser Advanced Drive Service pour répertorier les fichiers. Vous n'avez pas besoin d'une bibliothèque OAuth ou même d'obtenir un jeton OAuth. Vous devrez activer le service Advanced Drive à partir du menu "Ressources" et l'option de menu "Services Google avancés".

function listFiles() {
  var file;
  
  var query = 'trashed = false';
  var files;
  var pageToken;
  do {
    files = Drive.Files.list({
      q: query,
      maxResults: 100,
      pageToken: pageToken
    });
    if (files.items && files.items.length > 0) {
      for (var i = 0; i < files.items.length; i++) {
        file = files.items[i];
        Logger.log('%s (ID: %s)', file.title, file.id);
      }
    } else {
      Logger.log('No files found.');
    }
    pageToken = files.nextPageToken;
  } while (pageToken);
}


0 commentaires

0
votes

La note à la fin de la réponse de Tanalike a fonctionné ici - mon problème n'était pas d'ajouter l'adresse e-mail de mon compte de service à Google Drive. J'ai remplacé user_email par mon e-mail de service (et partagé cette adresse e-mail dans un dossier dans Drive) et cela a parfaitement fonctionné. Merci de votre aide!


1 commentaires

.setSubject sert à emprunter l'identité d'autres comptes (ne fonctionnera que si le compte de service a reçu une autorisation à l'échelle du domaine ). Pour accéder au Drive du compte de service, cette méthode n'est pas nécessaire (et ne doit en fait pas être utilisée). De plus, je ne vois aucune raison d'utiliser service.reset(); , J'envisagerais de supprimer cette ligne.