【问题标题】:Get refresh token using service account impersonation Google Drive使用服务帐户模拟 Google Drive 获取刷新令牌
【发布时间】:2024-01-23 20:03:01
【问题描述】:

我编写了一个脚本,它将在我们公司的多个用户 gdrive 中搜索文件。问题是该脚本可以工作,但只能运行一段时间,但随后会出现 HTTP 401 错误,这很可能是由于访问令牌过期。我正在使用启用了域范围委派的服务帐户,并使用 google.oauth2 python 库来创建 Drive 服务对象(参见下面的代码)。我想以编程方式获取刷新令牌并在当前令牌过期时生成新的访问令牌。问题是没有关于如何使用服务帐户执行此操作的文档。有正常的用户交互 oauth 流程。我的问题是如何使用驱动器对象来检索刷新令牌,然后创建新的访问令牌。我知道我将不得不以某种方式使用我的服务帐户的私钥,但不确定。

我一直在阅读这两个文档。 https://developers.google.com/identity/protocols/oauth2 https://developers.google.com/identity/protocols/oauth2/service-account

  • 使用模拟用户创建驱动服务对象
from google.oauth2 import service_account
import googleapiclient.discovery

def impersonate_user(user_to_impersonate, key_file, domain):
        scopes = ['https://www.googleapis.com/auth/drive',]

        if user_to_impersonate is None:
            raise InvalidDomainUser(f"{user_to_impersonate} is not a member of {domain}")

        if key_file is None:
            raise FileNotFoundError(f"{key_file} is not a valid service account file")

        delegated_credentials = service_account.Credentials.from_service_account_file(
            key_file, scopes=scopes)
        # Impersonate User.
        delegated_credentials = delegated_credentials.with_subject(user_to_impersonate)
        drive_service = googleapiclient.discovery.build('drive', 'v2', credentials=delegated_credentials)

        # Set new drive resource object
        return drive_service
  • 列出用户驱动器中的文件
service = impersonate_user(user_to_impersonate, key_file, domain):
children = service.children().list(folderId=folderId,maxResults=1000, **param).execute() 
for child in items:
            item = service.files().get(fileId=child['id']).execute()
            print(item.get("title", None))


【问题讨论】:

  • 当您说“脚本有效但仅在一段时间内”时,具体需要多少时间?创建服务后,您是否只使用一次列表?还是在很长一段时间后再次使用相同的服务对象?
  • 嘿,它会在大约 1 小时后过期。 3600 秒。之后,每个 api 调用都会导致 401 错误。我在一段时间内使用相同的驱动器对象,除非该用户驱动器中的文件或文件夹归其他人所有,在这种情况下,我将通过模拟新用户来重新实例化该对象
  • 为什么不在每次需要时(延长时间后)创建一个新的服务对象?
  • 另外,请确保 user_to_impersonate 始终是来自与服务帐户相同的域的用户。您可能会传递一个空值。但实际上您的情况听起来像是尽管创建了服务帐户凭据,但您的代码使用访问令牌而不是创建服务对象。
  • 嘿,我现在开始工作了。这是我的代码中的逻辑错误。但它现在似乎正在工作。感谢您的帮助!

标签: python google-drive-api google-oauth google-admin-sdk google-api-python-client


【解决方案1】:

冒充用户会生成一个过期的访问令牌。要获得新的访问令牌,您只需按照第一次的方式生成一个。服务帐户没有刷新令牌的概念,您只需使用您的凭据生成一个新的访问令牌。

来源:建Google Service Account support at Xkit

【讨论】:

    【解决方案2】:

    这是使用 python 的服务帐户的基本代码。您需要添加委托部分。

    只要您使用相同的服务,图书馆就应该在需要时为您获取新的访问令牌。它应该不会过期。

    """Hello drive"""
    
    from apiclient.discovery import build
    from oauth2client.service_account import ServiceAccountCredentials
    
    
    SCOPES = ['https://www.googleapis.com/auth/drive.readonly']
    KEY_FILE_LOCATION = '<REPLACE_WITH_JSON_FILE>'
    VIEW_ID = '<REPLACE_WITH_VIEW_ID>'
    
    
    def drive():
      """Initializes an drive service object.
    
      Returns:
        An authorized drive service object.
      """
      credentials = ServiceAccountCredentials.from_json_keyfile_name(
          KEY_FILE_LOCATION, SCOPES)
    
      # Build the service object.
      drive = build('drive', 'v3', credentials=credentials)
    
      return drive
    

    【讨论】:

    • 您好,是的,它似乎仍然在 1 小时后过期。我收到此错误&lt;HttpError 401 when requesting https://www.googleapis.com/drive/v2/files/fileidhere/children?maxResults=1000&amp;alt=json returned "Invalid Credentials"&gt; 在文件 lib\site-packages\googleapiclient\http.py
    最近更新 更多