带有 JWT 令牌的 Google Cloud Storage JSON API [英] Google Cloud Storage JSON API with JWT Token

查看:19
本文介绍了带有 JWT 令牌的 Google Cloud Storage JSON API的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用适用于 Google Cloud Storage 的 JSON API 从 Google Cloud Storage 检索文件.我不被允许使用 SDK.是否可以从 ServiceAccount.json 文件创建 JWT 并使用 JWT 访问 Google Cloud Storage 中的文件?我在 node.js 中有一个从服务帐户生成 JWT 的脚本,但我不确定观众是否正确

I'm trying to use the JSON API for Google Cloud Storage to retrieve a file from Google Cloud Storage. I am not allowed to use the SDKs. Is it possible to create a JWT from a ServiceAccount.json file and use the JWT to access files from Google Cloud Storage? I have a script in node.js that generates a JWT from the service account, but i'm not sure if the audience is right

const jwt = require('jsonwebtoken');
const serviceAccount = require('./serviceAccount.json');
const issuedAt = Math.floor(Date.now() / 1000);

const TOKEN_DURATION_IN_SECONDS = 3600;

let params = {
    'iss': serviceAccount.client_email,
    'sub': serviceAccount.client_email,
    'aud': serviceAccount.project_id,
    'iat': issuedAt,
    'exp': issuedAt + TOKEN_DURATION_IN_SECONDS,
};

let options = {
    algorithm: 'RS256',
    header: {
        'kid': serviceAccount.private_key_id,
        'typ': 'JWT',
        'alg': 'RS256',
    },
};

let token = jwt.sign(params, serviceAccount.private_key, options);
console.log(token);

然后我使用该 JWT 调用 Google Cloud Storage JSON API:

I then use that JWT to call the Google Cloud Storage JSON API:

https://www.googleapis.com/storage/v1/b/test

使用标题:Authorization Bearer {token}

这只会导致 Invalid Credentials 响应.

几个问题:

  • 我不确定在创建 JWT 时aud"应该是什么.我看过一些例子,其中它是一个 url,也是它的 projectId.都不适合我.
  • 其中一个 JSON API 示例说授权令牌应该是 oauth 令牌.我可以改用 JWT 还是需要使用 JWT 进行调用才能获取访问令牌?
  • 我的存储桶路径是否正确?存储桶路径的基本文件夹是您的 projectId 吗?我的路径应该是 /{projectId}/test.两种方法我都试过了,都没有.
  • I'm not sure what the 'aud' should be when creating the JWT. I've seen examples where it's a url and also where it's the projectId. Neither work for me.
  • One of the JSON API examples said the Authorization token should be an oauth token. Can I use a JWT instead or do I need to make a call using the JWT to get an access token?
  • Is my bucket path correct? Is the base folder for the bucket path your projectId? Should my path be /{projectId}/test. I've tried both and neither work.

回顾

这是一个 IoT 项目,我需要嵌入式设备才能从 Google Cloud Storage 下载文件.我需要创建一个门户网站以将文件上传到(使用 Firebase 函数)并将存储桶路径或私有/签名 URL 传递给设备.底线是我需要使用服务帐户密钥访问 Google Cloud Storage 存储桶.如果有嵌入式 SDK - 很好,但我找不到 C 的.我唯一的想法是使用 JSON API.如果有一种方法可以让我签署一个只能使用服务帐户访问的 URL - 也可以.

This is an IoT project and I need embedded devices to download files from Google Cloud Storage. I need to create a web portal to upload files to (using Firebase Functions) and pass to the device either a bucket path or a private/signed URL that. The bottom line being I need to access a Google Cloud Storage bucket using a service account key. If there is an embedded SDK - great, but I couldn't find one for C. My only thought was to use the JSON API. If there is a way I can sign a URL which can only be accessed using a service account - that works too.

谢谢!

推荐答案

是的,您可以从服务帐户 Json(或 P12)文件创建自己的签名 JWT,并将 JWT 交换为访问令牌,然后用作 授权:Bearer TOKEN

Yes, you can create your own Signed JWT from a service account Json (or P12) file and exchange the JWT for an Access Token that you then use as Authorization: Bearer TOKEN

我已经写了很多关于如何使用 Json 和 P12 凭据的文章.

I have written a number of articles on how to use Json and P12 credentials.

Google Cloud – 创建 OAuthREST API 调用的访问令牌

对于您的问题:

我不确定在创建 JWT 时aud"应该是什么.我见过示例,其中它是一个 url,也是它的 projectId.两者都不为我工作.

I'm not sure what the 'aud' should be when creating the JWT. I've seen examples where it's a url and also where it's the projectId. Neither work for me.

aud 设置为 "https://www.googleapis.com/oauth2/v4/token"

其中一个 JSON API 示例说授权令牌应该是oauth 令牌.我可以改用 JWT 还是需要使用获取访问令牌的 JWT?

One of the JSON API examples said the Authorization token should be an oauth token. Can I use a JWT instead or do I need to make a call using the JWT to get an access token?

某些 API 接受签名的 JWT,其他 API 则需要 OAuth 访问令牌.始终获取 OAuth 访问令牌更容易.在下面的示例代码中,我将向您展示如何操作.

Some APIs accept signed JWTs, others expect an OAuth Access Token. It is just easier to always obtain the OAuth Access Token. In my example code below, I show you how.

我的存储桶路径是否正确?存储桶路径的基本文件夹是您的项目编号?我的路径应该是/{projectId}/test.我都试过了都不行.

Is my bucket path correct? Is the base folder for the bucket path your projectId? Should my path be /{projectId}/test. I've tried both and neither work.

你的 url 看起来像这样(Python 字符串构建示例)

Your url shold look like this (Python string building example)

url = "https://www.googleapis.com/storage/v1/b?project=" + project

下面我将向您展示如何调用两个服务(GCE 和 GCS).大多数 Google API 将遵循类似的风格来构建 REST API 网址.

Below I show you how to call two services (GCE and GCS). Most Google APIs will follow similar styles for building the REST API urls.

从您问题中的代码来看,您错过了 OAuth 流程的最后一步.您需要将签名的 JWT 交换为访问令牌.

From the code in your question, you are missing the last step in the OAuth process. You need to exchange your Signed JWT for an Access Token.

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

这是一个完整的 Python 3.x 示例,它将列出 GCE 实例.此代码下方是显示 GCS 存储桶的更改.

Here is a complete Python 3.x example that will list GCE instances. Below this code are changes to display GCS Buckets.

'''
This program lists lists the Google Compute Engine Instances in one zone
'''

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('
', ''))

    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)

要改为显示 GCS Buckets,请修改代码:

To display GCS Buckets instead, modify the code:

# Create the HTTP url for the Google Storage REST API
url = "https://www.googleapis.com/storage/v1/b?project=" + project

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

s = content.decode('utf-8').replace('
', '')

j = json.loads(s)

print('')
print('Buckets')
print('----------------------------------------')
for item in j['items']:
    print(item['name'])

这篇关于带有 JWT 令牌的 Google Cloud Storage JSON API的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆