Python unauthorized_client:客户端无权使用此方法检索访问令牌

Python unauthorized_client:客户端无权使用此方法检索访问令牌,python,google-api,google-drive-api,google-oauth,Python,Google Api,Google Drive Api,Google Oauth,我是一名拥有近300名用户的GSuite管理员,正在从GSuite迁移。我需要下载他们创建/上传的所有用户文件 我从编写一个Python脚本开始,该脚本将在列表中显示用户文件,似乎我被压倒性的授权问题所困扰 我在Google控制台中创建了一个项目,并创建了一个服务帐户,其中勾选了私钥(基于json)和GSuite域范围的委派复选框 在我的GSuite管理面板中,我在Manage API access中将新创建的客户端ID和权限范围添加到这些范围中:https://www.googleapis.c

我是一名拥有近300名用户的GSuite管理员,正在从GSuite迁移。我需要下载他们创建/上传的所有用户文件

我从编写一个Python脚本开始,该脚本将在列表中显示用户文件,似乎我被压倒性的授权问题所困扰

  • 我在Google控制台中创建了一个项目,并创建了一个服务帐户,其中勾选了私钥(基于json)和GSuite域范围的委派复选框
  • 在我的GSuite管理面板中,我在Manage API access中将新创建的客户端ID和权限范围添加到这些范围中:
    https://www.googleapis.com/auth/drive,https://www.googleapis.com/auth/admin.datatransfer,https://www.googleapis.com/auth/admin.directory.user, https://www.googleapis.com/auth/admin.directory.group
  • 从文件上看很好()

  • 我正在从ServiceAccountCredentials创建一个资源对象,并分别基于API名称/版本“drive”和“v3”构建一个对象,并尝试根据Google的quickstart()获取文件列表:

  • 它看起来完全正确,但我收到以下错误消息:

    已连接到pydev调试器(build 181.5087.37)

    回溯(最近一次调用上次):文件 “/Applications/PyCharm.app/Contents/helpers/pydev/pydevd.py”,第行 1664年,在 main()文件“/Applications/PyCharm.app/Contents/helpers/pydev/pydevd.py”,第行 总的来说是1658 globals=debugger.run(setup['file'],None,None,is_module)文件“/Applications/PyCharm.app/Contents/helpers/pydev/pydevd.py”, 第1068行,运行中 pydev_imports.execfile(文件、全局、局部)#执行脚本文件 “/Applications/PyCharm.app/Contents/helpers/pydev/\u pydev\u imps/\u pydev\u execfile.py”, 第18行,在execfile中 exec(compile(contents+“\n”,file,'exec'),glob,loc)file“/Users/probe/Projects/drive_getter/src/dconnect.py”,第16行,在 pageSize=10,fields=“nextPageToken,files(id,name)”File”/Users/probe/Projects/drive\u getter/drive\u getter/lib/python3.6/site packages/googleapiclient/\u helpers.py”, 第130行,在位置_包装中 返回包装的(*args,**kwargs)文件“/Users/probe/Projects/drive\u getter/drive\u getter/lib/python3.6/site packages/googleapiclient/http.py”, 第835行,执行中 method=str(self.method),body=self.body,headers=self.headers)文件 “/Users/probe/Projects/drive_getter/drive_getter/lib/python3.6/site packages/googleapiclient/http.py”, 第162行,输入重试请求 resp,content=http.request(uri,method,*args,**kwargs)文件“/Users/probe/Projects/drive\u getter/drive\u getter/lib/python3.6/site packages/oauth2client/transport.py”, 第159行,在new_请求中 凭证._刷新(原始请求方法)文件“/Users/probe/Projects/drive\u getter/drive\u getter/lib/python3.6/site packages/oauth2client/client.py”, 第749行,输入刷新 self.\u do\u refresh\u request(http)文件“/Users/probe/Projects/drive\u getter/drive\u getter/lib/python3.6/site packages/oauth2client/client.py”, 第819行,在刷新请求中 引发HttpAccessTokenRefreshError(错误消息,状态=响应状态)oauth2client.client.HttpAccessTokenRefreshError:未经授权的\u客户端: 客户端无权使用此方法检索访问令牌

    你知道在这个过程中做错了什么吗?再一次-我的目标是列出并稍后下载所有GSuite用户的所有用户文件,因此我考虑循环我的用户电子邮件,并对所有用户应用相同的逻辑,直到我下载所有文件

    谢谢合作

    客户端无权使用此方法检索访问令牌

    Google DevelopePR控制台中有几种不同类型的客户端

    • 浏览器-用于web应用程序
    • 本机-用于已安装的应用程序
    • 服务帐户-用于服务器到服务器的通信
    • 流动的
    使用这些不同类型进行身份验证的代码是不同的,这是可以理解的

    您使用的代码似乎是带有服务帐户的python的正确代码。虽然
    from_json_keyfile_name
    接受p12文件而不是.json文件

    为客户提供的服务必须在corect中。返回Google开发者控制台创建一个服务帐户客户端并下载正确的.json文件


    我建议使用.json文件而不是p12文件。我怀疑谷歌将来会停止使用这些文件。

    解决方案很简单

    首先,据我所知,google.oauth2库仅在使用P12键并基于这些凭据构造对象时才支持域范围的委托函数

    其次,请注意你正在下载的p12密钥的文件名,我将密钥文件名重命名为较短的文件名,但没有注意Google在文件名中包含公钥指纹

    因此,解决方案是,按照我的问题帖子中描述的所有步骤,使用p12键创建服务帐户,勾选域范围的委派,工作代码如下所示:

    from googleapiclient.discovery import build
    from oauth2client.service_account import ServiceAccountCredentials
    
    SERVICE_ACCOUNT_EMAIL = "client-name@client-name.iam.gserviceaccount.com"
    PK12_FILE = "./private-key-original-filename.p12"
    PK12_PASSWORD = "notasecret"
    SCOPES = ['https://www.googleapis.com/auth/drive']
    
    def create_directory_service(user_email):
        credentials = ServiceAccountCredentials.from_p12_keyfile(
            SERVICE_ACCOUNT_EMAIL,
            PK12_FILE,
            PK12_PASSWORD,
            scopes=SCOPES
        )
    
        credentials = credentials.create_delegated(user_email)
    
        return build('drive', 'v3', credentials=credentials)
    
    
    bryan = create_directory_service('domain-user@your-domain.com')
    
    results = bryan.files().list(
        pageSize=10, fields="nextPageToken, files(id, name, mimeType, parents)"
    ).execute()
    
    items = results.get('files', [])
    
    print(items)
    

    好处:如果你想从GDrive下载文件并保留文件夹结构(Google不会告诉你文件哈希是否为文件夹),请使用mimeType extracted和parent ID构建父文件夹堆栈,在循环列表时自动创建它们,然后将文件放在各自的父ID中。

    您可以尝试使用
    fields=“files(ID,name)”
    仅此而已吗?有问题。如果我从oauth2client.service\u帐户导入ServiceAccountCredentials导入
    ,它具有credentials.create\u委托方法,允许我下载特定用户的文件,但此对象不支持JSON格式的服务帐户凭据,但当我使用您的导入时,我可以加载JSON格式的服务帐户凭据,
    
    from google.oauth2 import service_account
    
    SCOPES = ['https://www.googleapis.com/auth/sqlservice.admin']
    SERVICE_ACCOUNT_FILE = '/path/to/service.json'
    
    credentials = service_account.Credentials.from_service_account_file(
            SERVICE_ACCOUNT_FILE, scopes=SCOPES)
    
    from googleapiclient.discovery import build
    from oauth2client.service_account import ServiceAccountCredentials
    
    SERVICE_ACCOUNT_EMAIL = "client-name@client-name.iam.gserviceaccount.com"
    PK12_FILE = "./private-key-original-filename.p12"
    PK12_PASSWORD = "notasecret"
    SCOPES = ['https://www.googleapis.com/auth/drive']
    
    def create_directory_service(user_email):
        credentials = ServiceAccountCredentials.from_p12_keyfile(
            SERVICE_ACCOUNT_EMAIL,
            PK12_FILE,
            PK12_PASSWORD,
            scopes=SCOPES
        )
    
        credentials = credentials.create_delegated(user_email)
    
        return build('drive', 'v3', credentials=credentials)
    
    
    bryan = create_directory_service('domain-user@your-domain.com')
    
    results = bryan.files().list(
        pageSize=10, fields="nextPageToken, files(id, name, mimeType, parents)"
    ).execute()
    
    items = results.get('files', [])
    
    print(items)