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

查看:116
本文介绍了带有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下载文件.我需要创建一个Web门户以将文件上传到(使用Firebase Functions),然后将存储段路径或该URL的私有/签名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)文件创建自己的Signed JWT,并将JWT交换为访问令牌,然后将其用作Authorization: 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云–创建REST API调用的OAuth访问令牌

对于您的问题:

我不确定在创建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?我的路径应该是/{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.

您的网址保留看起来像这样(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流程的最后一步.您需要将Signed 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('\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)

要改为显示GCS存储桶,请修改代码:

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

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天全站免登陆