33

gcloud auth print-access-token给我一个不记名令牌,我以后可以使用;但是,这是一个 shell 命令。我如何通过 Google Cloud Python API 以编程方式获取一个?

我看到了一个使用oauth2client的先前示例,但现在已弃用。我将如何使用google.authoauthlib做到这一点?oauth2client

4

7 回答 7

37

虽然上面的答案提供了很多信息,但它错过了一个重要的点 - 从中​​获取google.auth.default()compute_engine.Credentials()不包含令牌的凭据对象。所以回到最初的问题是什么是程序化替代方案gcloud auth print-access-token,我的回答是:

import google.auth
import google.auth.transport.requests
creds, project = google.auth.default()

# creds.valid is False, and creds.token is None
# Need to refresh credentials to populate those

auth_req = google.auth.transport.requests.Request()
creds.refresh(auth_req)

# Now you can use creds.token

我正在使用官方的 google-auth 包和默认凭据,这将使您在本地开发和远程 GCE/GKE 应用程序中都可以使用。

太糟糕了,这没有正确记录,我不得不阅读 google-auth代码来弄清楚我们如何获取令牌。

于 2019-04-23T04:15:35.117 回答
35

答案取决于您的环境以及您希望如何创建/获取凭据。

什么是 Google Cloud 凭据?

Google Cloud 凭据是 OAuth 2.0 令牌。该标记至少有一个Access Token,可选的Refresh TokenClient ID Token和支持参数,例如expirationService Account EmailClient Email等。

Google Cloud API 中的重要项目是Access Token. 这个令牌是授权访问云的东西。此令牌可用于诸如 等curl软件之类的程序中python,并且不需要 SDK。Access Token用于 HTTP标头Authorization中。

什么是访问令牌?

访问令牌是由 Google 生成的不透明值,它派生自已签名的 JWT,更正确地称为 JWS。JWT 由标头和声明(有效负载)Json 结构组成。这两个 Json 结构使用服务帐户的私钥进行签名。这些值经过 base64 编码并连接起来以创建访问密钥。

访问令牌的格式是:base64(header) + '.' + base64(payload) + '.' + base64(signature).

这是一个示例 JWT:

标题:

{
  "alg": "RS256",
  "typ": "JWT",
  "kid": "42ba1e234ac91ffca687a5b5b3d0ca2d7ce0fc0a"
}

有效载荷:

{
  "iss": "myservice@myproject.iam.gserviceaccount.com",
  "iat": 1493833746,
  "aud": "myservice.appspot.com",
  "exp": 1493837346,
  "sub": "myservice@myproject.iam.gserviceaccount.com"
}

使用访问令牌:

将启动 VM 实例的示例。替换 PROJECT_ID、ZONE 和 INSTANCE_NAME。此示例适用于 Windows。

curl -v -X GET -H "Authorization: Bearer <access_token_here>" ^
https://www.googleapis.com/compute/v1/projects/%PROJECT_ID%/zones/%ZONE%/instances/%INSTANCE_NAME%/start

计算引擎服务帐号:

对于这种情况,达斯汀的回答是正确的,但为了完整起见,我将包括一些额外的信息。

这些凭据由 GCP 自动为您创建,并从 VM 实例元数据中获取。权限由Cloud API access scopesGoogle 控制台控制。

但是,这些凭据有一些限制。要修改凭据,您必须先停止 VM 实例。此外,并非所有权限(角色)都受支持。

from google.auth import compute_engine

cred = compute_engine.Credentials()

服务帐户凭据:

在您了解所有类型的凭证及其用例之前,这些凭证将用于除gcloud和之外的所有内容gsutil。了解这些凭据将使编写程序时使用 Google Cloud 变得更加简单。从 Google 服务帐户 Json 文件中获取凭据很容易。唯一需要注意的是凭据过期(通常为 60 分钟)并且需要刷新或重新创建。

gcloud auth print-access-token不推荐。服务帐户凭据是 Google 推荐的方法。

这些凭据由控制台、gcloud 或通过程序/API 创建。权限由 IAM 分配给贷方,并在 Compute Engine、App Engine、Firestore、Kubernetes 等以及 Google Cloud 之外的其他环境中发挥作用。这些凭据从 Google Cloud 下载并存储在 Json 文件中。注意scopes参数。这定义了授予结果凭证对象的权限。

SCOPES = ['https://www.googleapis.com/auth/sqlservice.admin']
SERVICE_ACCOUNT_FILE = 'service-account-credentials.json'

from google.oauth2 import service_account

cred = service_account.Credentials.from_service_account_file(
            SERVICE_ACCOUNT_FILE, scopes=SCOPES)

Google OAuth 2.0 凭据:

这些凭据源自完整的 OAuth 2.0 流程。这些凭据是在您启动浏览器以访问 Google 帐户以授权访问时生成的。这个过程要复杂得多,需要大量的代码来实现,并且需要一个内置的 Web 服务器来进行授权回调。

此方法提供了附加功能,例如能够在浏览器中运行所有内容,例如您可以创建云存储文件浏览器,但请注意了解安全隐患。此方法是用于支持 Google 登录等的技术。我喜欢在允许在网站等上发布之前使用此方法对用户进行身份验证。正确授权的 OAuth 2.0 身份和范围的可能性是无穷无尽的。

示例代码使用google_auth_oauthlib

from google_auth_oauthlib.flow import InstalledAppFlow

flow = InstalledAppFlow.from_client_secrets_file(
    'client_secrets.json',
    scopes=scope)

cred = flow.run_local_server(
    host='localhost',
    port=8088,
    authorization_prompt_message='Please visit this URL: {url}',
    success_message='The auth flow is complete; you may close this window.',
    open_browser=True)

使用库的示例代码requests_oauthlib

from requests_oauthlib import OAuth2Session

gcp = OAuth2Session(
        app.config['gcp_client_id'],
        scope=scope,
        redirect_uri=redirect_uri)

# print('Requesting authorization url:', authorization_base_url)

authorization_url, state = gcp.authorization_url(
                        authorization_base_url,
                        access_type="offline",
                        prompt="consent",
                        include_granted_scopes='true')

session['oauth_state'] = state

return redirect(authorization_url)


# Next section of code after the browser approves the request

token = gcp.fetch_token(
            token_url,
            client_secret=app.config['gcp_client_secret'],
            authorization_response=request.url)
于 2018-11-25T23:02:02.360 回答
12

在某些情况下,无法在服务器或容器上设置环境变量,同时需要 Bearer 访问令牌来调用 Google 云 API。我提出以下内容来解决此类问题:

# pip3 install google-auth
# pip3 install requests

import google.auth
import google.auth.transport.requests
from google.oauth2 import service_account

credentials = service_account.Credentials.from_service_account_file('/home/user/secrets/hil-test.json', scopes=['https://www.googleapis.com/auth/cloud-platform'])
auth_req = google.auth.transport.requests.Request()
credentials.refresh(auth_req)
credentials.token

最后一行将打印用于调用 Google 云 API 的访问令牌。将ya29<REDACTED>以下 curl 命令替换为来自 python 的打印标记作为测试:

curl https://example.googleapis.com/v1alpha1/projects/PROJECT_ID/locations -H "Authorization: Bearer ya29<REDACTED>"

执行 python 获取令牌然后在 BASH 中 curl 调用 API 可能没有意义。目的是演示获取令牌以调用可能没有任何 Python 客户端库但 REST API 的谷歌云 Alpha API。然后,开发人员可以使用Python requests HTTP 库来调用 API。

于 2021-04-13T06:25:23.637 回答
7
import google.auth
import google.auth.transport.requests


# getting the credentials and project details for gcp project
credentials, your_project_id = google.auth.default(scopes=["https://www.googleapis.com/auth/cloud-platform"])

#getting request object
auth_req = google.auth.transport.requests.Request()

print(credentials.valid) # prints False
credentials.refresh(auth_req) #refresh token
#cehck for valid credentials
print(credentials.valid)  # prints True
print(credentials.token) # prints token
于 2020-08-06T10:55:47.897 回答
1

这可能不是推荐的方法,但对于我的应用程序中的 Rest API,这是获取令牌的简单方法。

from subprocess import PIPE, Popen


def cmdline(command):
    process = Popen(
        args=command,
        stdout=PIPE,
        shell=True
    )
    return process.communicate()[0]


token = cmdline("gcloud auth application-default print-access-token")
print("Token:"+token)
于 2020-05-05T17:42:09.000 回答
0

在寻找一种无需创建服务帐户即可使用 python SDK 的方法时,我发现自己在这里。我想要一种在本地开发可以在云中运行的脚本的方法。我能够通过使用 gcloud 命令的工件来实现这一点:

export GOOGLE_APPLICATION_CREDENTIALS=~/.config/gcloud/legacy_credentials/<me>/adc.json
于 2019-09-02T22:07:09.623 回答
0

合并这篇文章和谷歌云文档的建议,我编写了一个返回令牌的辅助函数。如果可能,它会生成一个令牌,如果没有,它会从环境中获取它,然后检查它是否有效。

import google
import os
import requests

GOOGLE_APPLICATION_CREDENTIALS = "GOOGLE_APPLICATION_CREDENTIALS"
GCS_OAUTH_TOKEN = "GCS_OAUTH_TOKEN"
SCOPE = "https://www.googleapis.com/auth/cloud-platform"
URL = "https://www.googleapis.com/oauth2/v1/tokeninfo"
PAYLOAD = "access_token={}"
HEADERS = {"content-type": "application/x-www-form-urlencoded"}
OK = "OK"


def get_gcs_token():
    """
    Returns gcs access token.
    Ideally, this function generates a new token, requries that GOOGLE_APPLICATION_CREDENTIALS be set in the environment
    (os.environ).
    Alternatively, environment variable GCS_OAUTH_TOKEN could be set if a token already exists
    """
    if GOOGLE_APPLICATION_CREDENTIALS in os.environ:
        # getting the credentials and project details for gcp project
        credentials, your_project_id = google.auth.default(scopes=[SCOPE])

        # getting request object
        auth_req = google.auth.transport.requests.Request()
        credentials.refresh(auth_req)  # refresh token
        token = credentials.token
    elif GCS_OAUTH_TOKEN in os.environ:
        token = os.environ[GCS_OAUTH_TOKEN]
    else:
        raise ValueError(
            f"""Could not generate gcs token because {GOOGLE_APPLICATION_CREDENTIALS} is not set in the environment.
Alternatively, environment variable {GCS_OAUTH_TOKEN} could be set if a token already exists, but it was not"""
        )

    r = requests.post(URL, data=PAYLOAD.format(token), headers=HEADERS)
    if not r.reason == OK:
        raise ValueError(
            f"Could not verify token {token}\n\nResponse from server:\n{r.text}"
        )
    if not r.json()["expires_in"] > 0:
        raise ValueError(f"token {token} expired")
    return token
于 2020-12-10T08:25:07.890 回答