You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

在Google Cloud Run中通过Google OAuth 2.0完成身份验证并获取API凭证的方法

在Google Cloud Run中通过Google OAuth 2.0完成身份验证并获取API凭证的方法

兄弟,我太懂你刚接触API和服务器配置的迷茫了,尤其是在Cloud Run这种无GUI的容器环境里搞OAuth认证,简直是精准踩坑。你遇到的“could not locate runnable browser”错误,核心原因就是Cloud Run是纯后端的无状态容器,完全不支持任何图形界面,所以你代码里flow.run_local_server()这种需要弹出浏览器的授权流程肯定走不通。

下面给你两种最适配Cloud Run的解决方案,你可以根据自己的需求选:

一、优先推荐:使用GCP服务账号(最适合Cloud Run的原生方案)

因为Cloud Run本身就是GCP的托管服务,用服务账号来做身份验证是最省心、最安全的,完全不需要处理浏览器授权那一套。

具体操作步骤:

  1. 创建并配置服务账号
    去GCP控制台创建一个新的服务账号,给它分配Google Tasks API对应的权限(比如Tasks > Tasks Editor或者Tasks Viewer,根据你需要的操作权限来选)。
  2. 部署Cloud Run时指定服务账号
    部署你的服务到Cloud Run的时候,在“安全”配置项里,把刚才创建的服务账号设为这个Cloud Run服务的运行身份。
  3. 简化你的认证代码
    不需要再用本地的credentials.jsontoken.json了,直接用GCP的原生认证方式,代码可以改成这样:
    import google.auth
    from googleapiclient.discovery import build
    
    def authenticate():
        # 在Cloud Run中运行时,会自动从GCP元数据服务器获取凭证
        # 同时指定你需要的API权限范围
        creds, _ = google.auth.default(scopes=['https://www.googleapis.com/auth/tasks'])
        return creds
    
    这种方式还有个好处:不需要把任何密钥文件打包到你的Docker镜像里,完全靠GCP的内部身份机制,避免了密钥泄露的风险,这也是GCP官方推荐的“工作负载身份”模式。

二、如果必须访问特定用户的Tasks数据(用用户级OAuth):使用设备授权流

如果你要访问的是某个特定Google用户的Tasks数据,而不是服务账号自己的资源,那可以用设备授权流——这种方式不需要弹出浏览器,而是让用户在自己的设备上完成授权。

修改你的认证代码:

import os
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import Flow
from google.auth.transport.requests import Request

def authenticate():
    creds = None
    SCOPES = ['https://www.googleapis.com/auth/tasks']
    # 注意:Cloud Run是无状态的,token.json存在容器里重启就没了,最好改成存在Cloud Storage里
    if os.path.exists('token.json'):
        creds = Credentials.from_authorized_user_file('token.json', SCOPES)
    
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            # 用设备授权流替代本地浏览器授权
            flow = Flow.from_client_secrets_file(
                '/work/credentials.json',
                scopes=SCOPES,
                redirect_uri='urn:ietf:wg:oauth:2.0:oob'
            )
            # 获取授权URL和用户验证码
            auth_url, user_code = flow.authorization_url(prompt='consent')
            # 这里你需要把这两个信息传递给用户,比如通过你的服务API返回给前端,或者打印到Cloud Run日志里
            print(f"请在任意浏览器打开:{auth_url},然后输入验证码:{user_code}")
            # 等待用户完成授权后,获取最终的凭证
            # 注意:在Cloud Run里不能用input(),得通过API接口接收用户输入的授权码
            auth_code = input("请输入授权后得到的验证码:")
            flow.fetch_token(code=auth_code)
            creds = flow.credentials
        # 建议把token.json上传到Cloud Storage,而不是存在本地
        with open('token.json', 'w') as token:
            token.write(creds.to_json())
    return creds

注意事项:

  • Cloud Run是无状态的,容器重启后本地的token.json会消失,所以最好把token文件存在Cloud Storage里,每次认证时先从Cloud Storage下载,更新后再传回去。
  • 你需要做一个简单的前端或者接口,让用户能看到授权URL和验证码,并且能把授权后的验证码提交给你的服务,毕竟Cloud Run里没法用input()这种交互式输入。

总结

如果你的需求是访问服务账号可以操作的Tasks资源,优先选服务账号+工作负载身份的方案,这是最适配Cloud Run的;如果必须访问特定用户的个人Tasks数据,再用设备授权流,同时记得把token存在持久化存储里。

备注:内容来源于stack exchange,提问作者Mirkyly

火山引擎 最新活动