我已按照https://developers.google.com/accounts/docs/OAuth2ServiceAccount中的说明使用服务帐户对Google云端存储API进行身份验证。我试图在python中发送一个JWT到google的身份验证服务器,但是出了错误:
urllib2.HTTPError: HTTP Error 400: Bad Request
看起来我正在制作,签名或发送JWT的方式有问题吗?错误并不具体,因此它可能是该过程的任何部分。有没有人有任何想法?
import Crypto.PublicKey.RSA as RSA
import Crypto.Hash.SHA as SHA
import Crypto.Signature.PKCS1_v1_5 as PKCS1_v1_5
import base64
import json
import time
import urllib2
import urllib
# Settings
json_key_file = 'GooglePM-9f75ad112f87-service.json'
# Load the private key associated with the Google service account
with open(json_key_file) as json_file:
json_data = json.load(json_file)
key = RSA.importKey(json_data['private_key'])
# Create an PKCS1_v1_5 object
signer = PKCS1_v1_5.new(key)
# Encode the JWT header
header_b64 = base64.urlsafe_b64encode(json.dumps({'alg':'RS256','typ':'JWT'}))
# JWT claims
jwt = {
'iss': json_data['client_email'],
'scope': 'https://www.googleapis.com/auth/devstorage.read_write',
'aud': 'https://accounts.google.com/o/oauth2/token',
'exp': int(time.time())+3600,
'iat': int(time.time())
}
jwt_json = json.dumps(jwt)
# Encode the JWT claims
jwt_json_b64 = base64.urlsafe_b64encode(jwt_json)
# Sign the JWT header and claims
msg_hash = SHA.new(header_b64 + "." + jwt_json_b64)
signature_b64 = base64.urlsafe_b64encode(signer.sign(msg_hash))
# Make the complete message
jwt_complete = header_b64 + "." + jwt_json_b64 + "." + signature_b64
data = {'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
'assertion': jwt_complete}
f = urllib2.urlopen("https://accounts.google.com/o/oauth2/token", urllib.urlencode(data))
print f.read()
如果我尝试使用curl发布到服务器,则会收到无效授予错误:
(venv)$ curl -d 'grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Ajwt-bearer&assertion=eyJhbGciOiAiUlMyNTYiLCAidHlwIjogIkpXVCJ9.eyJpc3MiOiAiMTM1MDY3NjIyMTk4LWVhbWUwZnFqdTNvamRoZ29zdDg2dnBpdTBsYW91NnZlQGRldmVsb3Blci5nc2VydmljZWFjY291bnQuY29tIiwgInNjb3BlIjogImh0dHBzOi8vd3d3Lmdvb2dsZWFwaXMuY29tL2F1dGgvZGV2c3RvcmFnZS5yZWFkX3dyaXRlIiwgImF1ZCI6ICJodHRwczovL2FjY291bnRzLmdvb2dsZS5jb20vby9vYXV0aDIvdG9rZW4iLCAiZXhwIjogMTQwODY1MTU2OCwgImlhdCI6IDE0MDg2NDg1NTh9.HWC7h3QiOy7QsSuta4leq_Gjwmy9IdF-MUwflPhiohzAJ-Amykd56Ye4Y_Saf_sAc5STzOCmrSPzOTYvGXr6X_T_AmSTxXK2AJ2SpAiEUs2_Wp5h18xTUY3Y_hkKvSZLh5bRzeJ_0xRcmRIPE6tua0FHFwUDdnCIGdh4DGg6i4E%3D' https://accounts.google.com/o/oauth2/token
{
"error" : "invalid_grant"
}
答案 0 :(得分:8)
好的,这样做有更好的方法!谷歌已经有一个python客户端API来处理一些复杂性。安装google python客户端API后,以下代码可以运行:https://developers.google.com/api-client-library/python/guide/aaa_oauth
from oauth2client.client import SignedJwtAssertionCredentials
import json
import urllib
import urllib2
# Settings
json_key_file = 'GooglePM-9f75ad112f87-service.json'
# Load the private key associated with the Google service account
with open(json_key_file) as json_file:
json_data = json.load(json_file)
# Get and sign JWT
credential = SignedJwtAssertionCredentials(json_data['client_email'], json_data['private_key'], 'https://www.googleapis.com/auth/devstorage.read_write')
jwt_complete = credential._generate_assertion()
# Get token from server
data = {'grant_type': 'urn:ietf:params:oauth:grant-type:jwt-bearer',
'assertion': jwt_complete}
f = urllib2.urlopen("https://accounts.google.com/o/oauth2/token", urllib.urlencode(data))
print f.read()
答案 1 :(得分:3)
也许,稍微简单一些:
import oauth2client.service_account
jsonfile = 'GooglePM-9f7sdf342f87-service.json'
# use static method .from_json_keyfile_name(filename)
credentials = oauth2client.service_account.ServiceAccountCredentials.from_json_keyfile_name(jsonfile)
答案 2 :(得分:1)
你的第一个算法完全正常并且正常工作,但你需要SHA256,而不是SHA。谢谢你的代码。
答案 3 :(得分:1)
初始代码也可以在Python 3.6中使用。如果使用base64,只需使用字节而不是str:
<e><n>2320</n><h>-1950312402</h></e>
<e><n>410</n><h>103682488</h></e>
<e><n>4301</n><h>933882987</h></e>
<e><n>110</n><h>-2069728628</h></e>