使用Service Account讀取谷歌表格

前言

隨着谷歌表格API升級到第四個版本之後,雖然提供了更快的表格數據讀取API,可是還有就是須要受權才能讀取到數據,即便是發佈到網絡的表格。因此咱們在作這一升級的時候,嘗試了不少的方法,也走過了不少的坑,下面我就簡單總結一下。javascript

方案

首先我找到了讀取表格數據的API 接口:java

developers.google.com/sheets/api/…ios

該接口須要的參數以下(必傳的參數):git

{
    "spreadsheetId": "",
    "range": "",
    "access_token": ""
}
複製代碼

使用過的朋友都知道,spreadsheetId和range是表格的id和表格的tab範圍。可是access_token並非一個固定的東西,因此我研究了google獲取access_token的兩種方式(都是基於OAuth 2.0的):github

  1. 使用用戶本身的帳號,簡單來說就是通知用戶受權,而後用戶確認後能夠拿到用戶的access_token讀取該用戶擁有讀取權限的表格數據。
  2. 使用服務帳號,將表格共享給這個谷歌帳號,而後使用服務器登陸服務帳號,獲取服務帳號的access_token讀取表格數據。

剛開始的時候我使用了第一種方式,可是出現了下面的缺點:ajax

  1. 須要寫死一個帳號,每次都是用這個帳號進行受權。
  2. access_token 的有效期很短(通常是兩個小時),隔一段時間須要手動受權,須要人工的干預。
  3. 要是哪天個人帳號被刪除了就須要從新設置新的帳號,並生成新的項目配置。

後來看到谷歌在服務器受權的時候,建議使用服務帳號(雖然API KEY也能夠),就實現了服務端無用戶參與的受權。redis

實現

1、建立一個項目

在開發者控制檯建立一個項目npm

link:console.developers.google.com/projectcrea…json

填寫完必要的信息後,直接點擊建立便可(注意項目的id不能修改)。axios

2、開通Google Sheet API服務

在建立完帳號之後就會跳轉到該項目的dashboard,以下面的視圖,直接在搜索框搜索Google Sheet API,若是不開啓建立的服務帳號是沒有權限讀取表格數據的。

在API頁面直接點擊啓用便可開啓該項目的Sheet API功能。

3、生成一個服務帳號

開啓Sheet API之後會跳轉到Sheet API的配置頁面,咱們如今爲這個項目建立一個服務帳號。

首先按照標記點擊"憑據",而後點擊"API與服務中的憑據"來建立服務帳號。

咱們在這裏選擇建立"服務帳號密鑰";

4、生成憑據

點擊上面的"服務帳號密鑰"跳轉到了密鑰建立頁面,咱們選擇新的服務帳號,根據本身的要求進行填寫,以下所示。

這裏我選擇了JSON格式,方便Node.js(本次以Node.js做爲實踐)讀取;

點擊建立之後咱們會獲得一個json文件,注意改json文件必定要保存好了,後面的受權全靠它了。

接下來就開始編碼實現讀取的功能了;

5、開始編碼

下面是Node.js做爲實現,首先須要安裝googleapis,下面代碼是受權部分。

npm install googleapis --save
複製代碼
const {google} = require('googleapis');

// 後面的json文件就是咱們在上面第四步下載的json文件。 
const {client_email: email, private_key: key} = require('./service-account.json');

// 指定權限,這裏僅須要讀取權限就能夠了
const scopes = ['https://www.googleapis.com/auth/spreadsheets.readonly'];

// 全局存儲受權後的token信息,後面也能夠存儲到redis等緩存中,如今爲了測試,我就存儲在本地的變量中
let token = null;

module.exports = {
    authorize() {
        return new Promise((resolve) => {
            // 首先判斷有沒有token文件
            if (token) {
                const {access_token, expiry_date} = token;
                // 看看有沒有過時 + 1分鐘
                if (expiry_date > (new Date().getTime() + 60 * 1000)) {
                    return resolve(access_token);
                }
            }
            
            // 從新受權
            let jwtClient = new google.auth.JWT(email, null, key, scopes);
            // 直接能夠獲取到access_token,很方便,不須要人工干預
            jwtClient.authorize().then(data => {
                // 保存token到全局變量
                token = data;
                // 返回token
                resolve(data.access_token)
            }).catch(() => {
                resolve('');
            });
        });
    }
};
複製代碼

而後咱們經過上面的authorize能夠取到token信息,最後使用ajax客戶端來調用表格的接口,便可實現數據的讀取。

下面是讀取表格數據的實現:

module.exports = async function getSheetData({spreadsheetId, worksheets}) {
    const axios = require('axios');
    const qs = require('qs');
    const auth = require('../auth/jwtclient');
    const serviceEmailAddr = require('../auth/service-account').client_email;
    const token = await auth.authorize();
    const url = `https://sheets.googleapis.com/v4/spreadsheets/${spreadsheetId}/values:batchGet`;
    return await axios
        .get(url, {
            params: {access_token: token, ranges: worksheets},
            paramsSerializer(params) {
                return qs.stringify(params, {arrayFormat: 'repeat', encodeValuesOnly: true});
            }
        })
        .then(resp => resp.data.valueRanges)
        .catch(error => {
            if (error.response.status === 404) {
                return Promise.reject('表格不存在,請檢查表格id是否正確');
            }
            if (error.response.status === 403) {
                return Promise.reject('沒有權限訪問,請將表格分享給:' + serviceEmailAddr);
            }
            if (error.response.status === 400) {
                return Promise.reject(error.response.data.error.message.replace('Unable to parse range', '請檢查後面表格是否存在'));
            }
            Promise.reject(error.message);
        });
};
複製代碼

爲了保證隱私,我沒有上傳項目配置的json文件;

參考實現:github.com/gslnzfq/dev…

6、測試

若是讀取數據的時候,google返回了403,那多是由於你沒有將表格共享給服務帳號,查看服務帳號:

console.developers.google.com/iam-admin/s…

在上面選擇你的項目,就能看到右邊的電子郵件,將谷歌表格共享給改郵箱就能夠訪問了。

參考文檔

相關文章
相關標籤/搜索