我收到错误"不支持的授权类型"当我尝试使用curl为服务帐户请求OAuth令牌时。我关注服务帐户的OAuth 2.0示例(https://developers.google.com/identity/protocols/OAuth2ServiceAccount),我认为我已正确设置了所有内容。我在Google Cloud中设置了服务帐户,并且我在OAuth请求中使用该电子邮件地址。
文档说使用URL编码的授权类型" urn:ietf:params:oauth:grant-type:jwt-bearer"但是,如果这是授权类型的唯一选项或其他选项可能是什么,则不清楚。
我正在发送base64编码标头
{"alg":"RS256","typ":"JWT"}
和"。" 和base64编码的声明
{
"iss":"chargepubadmin@xxxxxxxx.iam.gserviceaccount.com",
"scope":"https://www.googleapis.com/auth/pubsub",
"aud":"https://www.googleapis.com/oauth2/v4/token",
"exp":1497159875,
"iat":1497156275
}
和"。" 和base64编码签名
{base64 header}.{base64 claims}
curl -X POST -d 'grant_type=http%3A%2F%2Foauth.net%2Fgrant_type%2Fdevice%2F1.0%26assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.ew0KICAiaXNzIjoiY2.......' "https://www.googleapis.com/oauth2/v4/token"
我正在使用与示例base64编码匹配的在线base64编码工具。
任何人都可以告诉我授权类型是什么或应该是什么?
答案 0 :(得分:1)
应在REST API urn:ietf:params:oauth:grant-type:jwt-bearer
部分下将授权类型设置为Making the access token request
文档here。
如果您使用google-auth
库自动处理解析私钥json文件,获取访问令牌,刷新它们并实际将它们作为请求的一部分包含在内,那将非常简单和容易。< / p>
您只需提供请求URL和正文,图书馆负责其余部分。这是一个简化的例子:
#!/usr/bin/env python
from google.auth.transport.requests import AuthorizedSession
from google.oauth2.service_account import Credentials
# BEGIN CONFIGURATION - change as needed.
# Path to the JSON file containing the service account private key and email.
PRIVATE_KEY_JSON = '/path/to/json/file'
# The API scope this token will be valid for.
API_SCOPES = ['https://www.googleapis.com/auth/pubsub']
# END CONFIGURATION
if __name__ == '__main__':
credentials = Credentials.from_service_account_file(
PRIVATE_KEY_JSON, scopes=API_SCOPES)
authed_session = AuthorizedSession(credentials)
url = 'https://pubsub.googleapis.com/v1/<SOMETHING>'
response = authed_session.get(url)
print str(response.content)
如果你不想使用任何额外的库,但可以使用标准的python库,这里是一个Python的工作样本(用我自己的服务帐户亲自测试)(支持2.x和3.x版本) )负责所有步骤:
#!/usr/bin/env python
import Crypto.PublicKey.RSA as RSA
import Crypto.Hash.SHA256 as SHA
import Crypto.Signature.PKCS1_v1_5 as PKCS1_v1_5
import base64
import json
import time
try:
from urllib.request import urlopen
except ImportError:
from urllib2 import urlopen
try:
from urllib.parse import urlencode
except ImportError:
from urllib import urlencode
# BEGIN CONFIGURATION - change as needed.
# Path to the JSON file containing the service account private key and email.
PRIVATE_KEY_JSON = '/path/to/json/file'
# The API scope this token will be valid for.
API_SCOPE = 'https://www.googleapis.com/auth/pubsub'
# The validity of the token in seconds. Max allowed is 3600s.
ACCESS_TOKEN_VALIDITY_SECS = 3600
# END CONFIGURATION
class OauthAccessTokenGetter:
"""Fetches a new Google OAuth 2.0 access token.
The code is based on the steps described here: https://developers.go
ogle.com/identity/protocols/OAuth2ServiceAccount#authorizingrequests
"""
ACCESS_TOKEN_AUD = 'https://www.googleapis.com/oauth2/v4/token'
REQUEST_URL = 'https://www.googleapis.com/oauth2/v4/token'
GRANT_TYPE = 'urn:ietf:params:oauth:grant-type:jwt-bearer'
def __init__(self, private_key_json_file, scope, token_valid_secs=3600):
self.private_key_json = self.LoadPrivateKeyJsonFromFile(
private_key_json_file)
self.scope = scope
self.token_valid_secs = token_valid_secs
@classmethod
def Base64UrlEncode(cls, data):
"""Returns the base64url encoded string for the specified data."""
return base64.urlsafe_b64encode(data)
@classmethod
def LoadPrivateKeyJsonFromFile(cls, private_key_json_file):
"""Returns JSON object by parsing the specified private key JSON
file."""
with open(private_key_json_file) as private_key_json_file:
return json.load(private_key_json_file)
def GetPrivateKey(self):
"""Returns the imported RSA private key from the JSON data."""
return RSA.importKey(self.private_key_json['private_key'])
def GetSigner(self):
"""Returns a PKCS1-V1_5 object for signing."""
return PKCS1_v1_5.new(self.GetPrivateKey())
@classmethod
def GetEncodedJwtHeader(cls):
"""Returns the base64url encoded JWT header."""
return cls.Base64UrlEncode(json.dumps({'alg': 'RS256', 'typ': 'JWT'}).encode('utf-8'))
def GetEncodedJwtClaimSet(self):
"""Returns the base64url encoded JWT claim set."""
current_time_secs = int(time.time())
jwt_claims = {
'iss': self.private_key_json['client_email'],
'scope': self.scope,
'aud': self.ACCESS_TOKEN_AUD,
'exp': current_time_secs + self.token_valid_secs,
'iat': current_time_secs
}
return self.Base64UrlEncode(json.dumps(jwt_claims).encode('utf-8'))
def GetJwtSignature(self, message):
"""Returns signature of JWT as per JSON Web Signature (JWS) spec."""
signed_message = self.GetSigner().sign(SHA.new(message))
return self.Base64UrlEncode(signed_message)
def GetSignedJwt(self):
"""Returns signed JWT."""
header = self.GetEncodedJwtHeader()
jwt_claim_set = self.GetEncodedJwtClaimSet()
signature = self.GetJwtSignature(header + b'.' + jwt_claim_set)
return header + b'.' + jwt_claim_set + b'.' + signature
def SendRequest(self, body):
"""Returns the response by sending the specified request."""
return urlopen(self.REQUEST_URL, urlencode(body).encode('utf-8')).read()
def GetAccessToken(self):
"""Returns the access token."""
body = {
'grant_type': self.GRANT_TYPE,
'assertion': self.GetSignedJwt()
}
response = json.loads(self.SendRequest(body))
return response['access_token']
if __name__ == '__main__':
print (OauthAccessTokenGetter(PRIVATE_KEY_JSON, API_SCOPE,
ACCESS_TOKEN_VALIDITY_SECS).GetAccessToken())
获得访问令牌后,您需要将其作为Bearer
标头包含在您发送的described here请求中。
GET /drive/v2/files HTTP/1.1
Authorization: Bearer <access_token>
Host: www.googleapis.com/
等同于卷曲:
curl -H "Authorization: Bearer <access_token>" https://www.googleapis.com/drive/v2/files
尽管described here可以使用access_token=
参数指定令牌,但至少对于Google Compute Engine API我无法使用它,可能适用于PubSub,但discovery doc for PubSub API 1}}标题方法总是在我的经验中起作用。
更新根据discovery doc for Compute Engine APIs,Bearer
似乎有一个查询参数,所以它也可以很好地运作。
access_token=
而{{3}}表示使用了"access_token": {
"description": "OAuth access token.",
"type": "string",
"location": "query"
},
查询参数,而且我确实验证了它是否有效。
oauth_token