簡體   English   中英

如何使用 REST API 從服務帳戶憑據創建訪問令牌?

[英]How do I create an Access Token from Service Account Credentials using REST API?

我在 Google Cloud Platform 中創建了一個服務帳戶並下載了 JSON 格式的私鑰。 我正在嘗試通過 REST API 創建計算資源。 出於身份驗證目的,我需要一個 AccessToken,需要將其設置為創建計算資源 REST API 的標頭。 是否有 REST API 從私鑰獲取訪問令牌(不使用 SDK 或 Google 客戶端)?

以下示例向您展示了在不使用 Python SDK 的情況下調用 Google Cloud API 的幾個重要步驟。 類似的代碼幾乎適用於任何語言(c#、java、php、nodejs)。

使用您的服務帳戶 Json 文件的文件名、您的 Google 區域和您的項目 ID 更改源代碼。

此示例將列出指定項目的一個區域中的實例。 通過這個示例,您將了解調用 API 來創建 GCE 實例的框架。

此代碼將向您展示如何:

  1. 如何從 Json 文件加載服務帳戶憑據。
  2. 如何提取用於簽署請求的私鑰。
  3. 如何為 Google Oauth 2.0 創建 JWT(Json Web Token)。
  4. 如何設置 Google 范圍(權限)。
  5. 如何簽署 JWT 以創建 Signed-JWT (JWS)。
  6. 如何將 Signed-JWT 交換為 Google OAuth 2.0 訪問令牌。
  7. 如何設置過期時間。 該程序默認為 3600 秒(1 小時)。
  8. 如何調用 Google API 並設置授權標頭。
  9. 如何處理返回的Json結果並顯示每個實例的名稱。

Python 3.x 中的示例程序:

'''
This program lists lists the Google Compute Engine Instances in one zone
'''
# Author: John Hanley
# https://www.jhanley.com

import time
import json
import jwt
import requests
import httplib2

# Project ID for this request.
project = 'development-123456'

# The name of the zone for this request.
zone = 'us-west1-a'

# Service Account Credentials, Json format
json_filename = 'service-account.json'

# Permissions to request for Access Token
scopes = "https://www.googleapis.com/auth/cloud-platform"

# Set how long this token will be valid in seconds
expires_in = 3600   # Expires in 1 hour

def load_json_credentials(filename):
    ''' Load the Google Service Account Credentials from Json file '''

    with open(filename, 'r') as f:
        data = f.read()

    return json.loads(data)

def load_private_key(json_cred):
    ''' Return the private key from the json credentials '''

    return json_cred['private_key']

def create_signed_jwt(pkey, pkey_id, email, scope):
    ''' Create a Signed JWT from a service account Json credentials file
    This Signed JWT will later be exchanged for an Access Token '''

    # Google Endpoint for creating OAuth 2.0 Access Tokens from Signed-JWT
    auth_url = "https://www.googleapis.com/oauth2/v4/token"

    issued = int(time.time())
    expires = issued + expires_in   # expires_in is in seconds

    # Note: this token expires and cannot be refreshed. The token must be recreated

    # JWT Headers
    additional_headers = {
            'kid': pkey_id,
            "alg": "RS256",
            "typ": "JWT"    # Google uses SHA256withRSA
    }

    # JWT Payload
    payload = {
        "iss": email,       # Issuer claim
        "sub": email,       # Issuer claim
        "aud": auth_url,    # Audience claim
        "iat": issued,      # Issued At claim
        "exp": expires,     # Expire time
        "scope": scope      # Permissions
    }

    # Encode the headers and payload and sign creating a Signed JWT (JWS)
    sig = jwt.encode(payload, pkey, algorithm="RS256", headers=additional_headers)

    return sig

def exchangeJwtForAccessToken(signed_jwt):
    '''
    This function takes a Signed JWT and exchanges it for a Google OAuth Access Token
    '''

    auth_url = "https://www.googleapis.com/oauth2/v4/token"

    params = {
        "grant_type": "urn:ietf:params:oauth:grant-type:jwt-bearer",
        "assertion": signed_jwt
    }

    r = requests.post(auth_url, data=params)

    if r.ok:
        return(r.json()['access_token'], '')

    return None, r.text

def gce_list_instances(accessToken):
    '''
    This functions lists the Google Compute Engine Instances in one zone
    '''

    # Endpoint that we will call
    url = "https://www.googleapis.com/compute/v1/projects/" + project + "/zones/" + zone + "/instances"

    # One of the headers is "Authorization: Bearer $TOKEN"
    headers = {
        "Host": "www.googleapis.com",
        "Authorization": "Bearer " + accessToken,
        "Content-Type": "application/json"
    }

    h = httplib2.Http()

    resp, content = h.request(uri=url, method="GET", headers=headers)

    status = int(resp.status)

    if status < 200 or status >= 300:
        print('Error: HTTP Request failed')
        return

    j = json.loads(content.decode('utf-8').replace('\n', ''))

    print('Compute instances in zone', zone)
    print('------------------------------------------------------------')
    for item in j['items']:
        print(item['name'])

if __name__ == '__main__':
    cred = load_json_credentials(json_filename)

    private_key = load_private_key(cred)

    s_jwt = create_signed_jwt(
            private_key,
            cred['private_key_id'],
            cred['client_email'],
            scopes)

    token, err = exchangeJwtForAccessToken(s_jwt)

    if token is None:
        print('Error:', err)
        exit(1)

    gce_list_instances(token)

有關詳細信息,請訪問我的博客。 我寫這樣的文章並發布源代碼,以幫助其他人了解如何為雲編寫軟件。

www.jhanley.com

注意:如評論中所述,這實際上不是問題的解決方案,因為它使用 SDK。 無論如何,由於答案似乎對其他用戶有用,我沒有刪除它

有一種更簡單的方法可以使用 Google 庫從服務帳戶生成令牌

from google.auth.transport import requests
from google.oauth2 import service_account

CREDENTIAL_SCOPES = ["https://www.googleapis.com/auth/cloud-platform"]
CREDENTIALS_KEY_PATH = '/PATH/TO/SERVICE_ACCOUNT.json'

def get_service_account_token():
  credentials = service_account.Credentials.from_service_account_file(
          CREDENTIALS_KEY_PATH, scopes=CREDENTIAL_SCOPES)
  credentials.refresh(requests.Request())
  return credentials.token

或者如果你想使用默認身份驗證

import google
from google.auth.transport import requests

CREDENTIAL_SCOPES = ["https://www.googleapis.com/auth/cloud-platform"] 

def get_default_token():
  credentials, project_id = google.auth.default(scopes=CREDENTIAL_SCOPES)
  credentials.refresh(requests.Request())
  return credentials.token

創建credentials對象時,令牌為空,但在刷新credentials后,它包含可用作 API 請求標頭的訪問令牌

使用JAVA的相同解決方案

import com.google.auth.oauth2.GoogleCredentials;
import java.io.FileInputStream;
import java.io.IOException;

public class GoogleHelper {
    public static String getAccessToken() throws IOException {
        return GoogleCredentials
                .fromStream(new FileInputStream("/PATH/TO/SERVICE_ACCOUNT.json"))
                .createScoped("https://www.googleapis.com/auth/cloud-platform")
                .refreshAccessToken()
                .getTokenValue();
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM