Google OAuth 中不支持的授权类型

问题描述 投票:0回答:1

当我尝试使用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":"[email protected]",
  "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 编码工具。

任何人都可以告诉我补助金类型是什么或应该是什么?

oauth google-cloud-platform
1个回答
1
投票

授权类型应设置为 REST API

urn:ietf:params:oauth:grant-type:jwt-bearer
部分下Making the access token request记录的
此处

使用 google-auth 库的工作示例

如果您使用

google-auth
库,它会自动解析私钥 json 文件、获取访问令牌、刷新它们并实际将它们包含在请求中,这将非常容易和简单。

您只需提供请求 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
标头包含在您发送的请求中,如此处所述

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

虽然描述在这里,您可以使用

access_token=
参数指定令牌,但我无法让它至少在Google计算引擎API上工作,可能它与PubSub一起工作,但是
Bearer
标头方法已经起作用根据我的经验,总是如此。

更新:根据PubSub API的发现文档,似乎有一个

access_token=
的查询参数,所以它也可能很好用。

"access_token": {
      "description": "OAuth access token.",
      "type": "string",
      "location": "query"
    },

计算引擎 API 的发现文档指示使用

oauth_token
查询参数,我确实验证了它是否有效。

"oauth_token": {
   "type": "string",
   "description": "OAuth 2.0 token for the current user.",
   "location": "query"
  },
© www.soinside.com 2019 - 2024. All rights reserved.