如何使用 Javascript 从 Google Api 检索服务帐户 OAuth2 令牌?

How can I retrieve a service account OAuth2 token from Google Api with Javascript?

我需要使用 google 项目服务帐户来使用 JavaScript 访问 google API。为了做到这一点,我需要 OAuth2 到 google API 服务器来获取授权令牌。

我知道 Google 提供了一个用于节点服务器的库 (GAPI),但我需要一个可以在其他安全 JavaScript 环境中工作的解决方案。

这个任务有两个主要部分。

  1. 正在配置
  2. 编码

首先是配置步骤。

  • 如果您没有 google 帐户:
    1. 导航到 google.com
    2. 查找并单击 "Sign In"
    3. 点击"More Options"
    4. 点击"Create Account"
    5. 按照步骤创建一个帐户
  • 导航到 api 仪表板:console.developers.google.com/apis/dashboard
  • Select 或者点击当前项目创建一个项目。我展示的项目名为 "My Project"

  • 单击 并启用您计划使用的 API

  • 导航到凭据部分:console.developers.google.com/apis/credentials
  • 单击 和 select "Service account key"
  • 确保 "Key Type" 为 "Json" 并单击 "Create"。你key/cert会自动下载

现在是编码部分。

  • 首先下载jsrsasign并添加对"jsrsasign-all-min.js"的引用。如果需要,您可以从 github
  • 下载 "jsrsasign-all-min.js"
  • 第二次使用您的 cert/key(之前下载)更新以下脚本:

    function postJWT(jwt, callback) {
        var xhttp = new XMLHttpRequest();
        xhttp.onreadystatechange = function () {
            if (this.readyState == 4) {
                if (this.status == 200 && callback) {
                    callback(this.responseText);
                    return;
                }
                if (console) console.log(this.responseText);
            }
        };
        var parameters = "grant_type=" + encodeURIComponent("urn:ietf:params:oauth:grant-type:jwt-bearer") + "&assertion=" + encodeURIComponent(jwt);
        xhttp.open("POST", "https://www.googleapis.com/oauth2/v4/token", true);
        xhttp.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
        xhttp.send(parameters);
    }
    
    function getCert() {
        var cert = //your json key (downloaded earlier) goes here
            {
                "type": "service_account",
                "project_id": "proj..",
                "private_key_id": "e18..",
                "private_key": "-----BEGIN PRIVATE KEY-----\nMII..==\n-----END PRIVATE KEY-----\n",
                "client_email": "service-account@...iam.gserviceaccount.com",
                "client_id": "5761..",
                "auth_uri": "https://accounts.google.com/o/oauth2/auth",
                "token_uri": "https://accounts.google.com/o/oauth2/token",
                "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
                "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/..service-account%40...iam.gserviceaccount.com"
            };      
        return cert;
    }
    function getJWT() {
        var cert = getCert();
        var key = KEYUTIL.getKey(cert.private_key);
        var headers = { "alg": "RS256", "typ": "JWT" };
        var issued = Math.floor(new Date().getTime()/1000);
    
        var claims = {
            "iss": cert.client_email,
            "scope": "https://www.googleapis.com/auth/analytics.readonly",
            "aud": "https://www.googleapis.com/oauth2/v4/token",
            "exp": issued + 3600,
            "iat": issued
        };
    
        var jwt = KJUR.jws.JWS.sign(headers.alg, headers, JSON.stringify(claims), key);
        return jwt;
    }
    
  • 当您测试您的代码时,您应该会收到一个带有身份验证令牌的 json 对象。您可以像这样测试您的实现:

    postJWT(getJWT(text), function(){
        let token = JSON.parse(response).access_token;
        //Do your api calls here using the token. 
        //Reuse the token for up to 1 hour.
    });
    

这是一个成功的例子 json 带有令牌的对象:

{
    "access_token": "ya29.c.ElkABZznrLNLK6ZAq2ybiH5lsRJpABE8p7MlZZJ0WCKcDNDv75lh-o1iRX__uMNUKSySiawm4YJGsbfqJH2JH61nRK6O2m0GJR7DgkEmo6ZlKtrvzke9C3xpwA",
    "token_type": "Bearer",
    "expires_in": 3600
}

请注意,此方法要求 key/cert 可从您的 javascript 环境访问。如果这个环境是 public 你的 api 是易受攻击的。