代码之家  ›  专栏  ›  技术社区  ›  Dylan Nina

使用JWT触发Google云函数

  •  0
  • Dylan Nina  · 技术社区  · 2 年前

    我正在尝试使用HTTP请求和服务帐户触发谷歌云功能。 我遵循以下步骤:

    1. 创建服务帐户
    2. 下载JSON密钥文件
    3. 创建一个需要身份验证的谷歌云函数(这是一个只返回“Hello world!”的测试函数)
    4. 在“云函数权限”中,我添加了我的服务帐户和“云函数调用器”角色

    如果我使用此服务帐户生成身份令牌(gcloud auth print identity token)并使用它触发我的云功能(使用 Authorization: Bearer $ID_TOKEN 在页眉中)它按预期工作。 但现在我想在生产中做到这一点。所以我所做的就是生成一个JWT,用它来获取一个访问令牌,并使用这个访问令牌,就像我对身份令牌所做的一样,但我得到了401个未经授权的响应。

    这是我的代码(Python)

    import jwt
    import time
    import requests
    
    # These elements are found in the service account JSON file (step 2)
    PRIVATE_KEY_ID_FROM_JSON = "123ab4cdefghi56jk789123456789f123456m7n"
    PRIVATE_KEY_FROM_JSON = "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----"
    SERVICE_ACCOUNT_EMAIL = "ACCOUNT_NAME@PROJECT_ID.iam.gserviceaccount.com"
    
    # Create JWT
    iat = int(time.time())
    exp = iat + 3600
    
    payload = {
        'iss': SERVICE_ACCOUNT_EMAIL,
        'sub': SERVICE_ACCOUNT_EMAIL,
        'aud': "https://www.googleapis.com/oauth2/v4/token",
        'target_audience ': 'https://REGION-PROJECT_ID.cloudfunctions.net/FUNCTION_NAME',
        'iat': iat,
        'exp': exp,
        "scope": "https://www.googleapis.com/auth/cloud-platform"
    }
    additional_headers = {'kid': PRIVATE_KEY_ID_FROM_JSON}
    
    signed_jwt = jwt.encode(
        payload,
        PRIVATE_KEY_FROM_JSON,
        headers=additional_headers,
        algorithm='RS256'
    )
    
    # Use JWT to get access token
    resp = requests.post(
        f"https://www.googleapis.com/oauth2/v4/token"
        f"?grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion={signed_jwt}",
        headers={
            "Authorization": f"Bearer {signed_jwt}",
            "Content-Type": "application/x-www-form-urlencoded"
        }
    )
    
    access_token = resp.json()["access_token"]
    
    # Trigger Cloud Function using this access token
    resp_cf = requests.post(
        "https://europe-west1-cuure-265415.cloudfunctions.net/Test_service_account",
        headers={
            "Authorization": f"Bearer {access_token}"
        }
    )
    
    print(resp_cf.content)
    

    结果如下

    b'\n<html><head>\n<meta http-equiv="content-type" content="text/html;charset=utf-8">\n<title>401 Unauthorized</title>\n</head>\n<body text=#000000 bgcolor=#ffffff>\n<h1>Error: Unauthorized</h1>\n<h2>Your client does not have permission to the requested URL <code>/CLOUD FUNCTION NAME</code>.</h2>\n<h2></h2>\n</body></html>\n'
    

    我不想使用Python库来用服务帐户验证我的请求,因为我的目标是能够在Bubble中重现这一点。io,一个无代码开发平台。

    有人知道我做错了什么吗?

    0 回复  |  直到 2 年前
        1
  •  0
  •   Divyani Yadav    2 年前

    如前所述 Answer :

    有三种类型的OAuth令牌。刷新令牌,访问令牌, 身份令牌。您正在尝试使用OAuth访问令牌,而不是 OAuth身份标识。对于授权,谷歌云功能 在authorization:bearer HTTP头中使用OAuth标识令牌。

    你也可以参考 documentation answer 其中,将自签名JWT交换为谷歌签名的ID令牌得到了很好的解释。

    您可以使用IAM角色管理对HTTP云功能的访问。你 将要分配角色/云功能。调用程序角色 服务帐户,并让调用方向提供oauth凭据 授权标头中的函数。