Google api 使用Google管理员目录API使用Google ServiceAccountCredential登录需要401

Google api 使用Google管理员目录API使用Google ServiceAccountCredential登录需要401,google-api,google-oauth,google-admin-sdk,google-api-dotnet-client,google-workspace,Google Api,Google Oauth,Google Admin Sdk,Google Api Dotnet Client,Google Workspace,我尝试了下面列出的简单示例: 不同之处在于我生成了一个服务帐户凭据,并将其分配为具有项目所有者角色的代理,因此它具有完全访问权限。我还为它分配了适当的作用域名称空间 在这里,它可以访问orgunits,这就是我试图在目录API中列出的内容 这是我的服务帐户 这是我的证件 我下载了凭证的JSON并将其添加到我的项目中。我可以通过检查调试器来确认代码加载ServiceAccountCredential并成功地进行身份验证并获取访问令牌 但随后我将凭证传递给服务初始值设定项,当我创建并执行一个请求时,

我尝试了下面列出的简单示例:

不同之处在于我生成了一个服务帐户凭据,并将其分配为具有项目所有者角色的代理,因此它具有完全访问权限。我还为它分配了适当的作用域名称空间

在这里,它可以访问orgunits,这就是我试图在目录API中列出的内容

这是我的服务帐户

这是我的证件

我下载了凭证的JSON并将其添加到我的项目中。我可以通过检查调试器来确认代码加载ServiceAccountCredential并成功地进行身份验证并获取访问令牌

但随后我将凭证传递给服务初始值设定项,当我创建并执行一个请求时,它会失败

{"Google.Apis.Requests.RequestError\r\nLogin Required [401]\r\nErrors [\r\n\tMessage[Login Required] Location[Authorization - header] Reason[required] Domain[global]\r\n]\r\n"}
代码如下:

using Google.Apis.Auth.OAuth2;
using Google.Apis.Services;
using System;
using System.Collections.Generic;
using System.IO;

namespace DirectoryQuickstart
{
    class Program
    {
        static string[] Scopes = { DirectoryService.Scope.AdminDirectoryUser, DirectoryService.Scope.AdminDirectoryOrgunit };
        static string ApplicationName = "slea-crm";
        static string Secret = "gsuite-secret.json";

        static void Main(string[] args)
        {

            ServiceAccountCredential sac = GoogleCredential.FromFile(Secret).CreateScoped(Scopes).UnderlyingCredential as ServiceAccountCredential;

            var token = sac.GetAccessTokenForRequestAsync().Result;

            // Create Directory API service.
            var service = new DirectoryService(new BaseClientService.Initializer()
            {
                HttpClientInitializer = sac,

                ApplicationName = ApplicationName,
            });

            OrgunitsResource.ListRequest request = service.Orgunits.List(customerId: "REDACTED");
            IList<OrgUnit> orgUnits = request.Execute().OrganizationUnits;

            if (orgUnits != null && orgUnits.Count > 0)
            {
                foreach (var orgUnit in orgUnits)
                {
                    Console.WriteLine("{0} ({1})", orgUnit.Name, orgUnit.OrgUnitPath);
                }
            }
            else
            {
                Console.WriteLine("No orgunits found.");
            }
            Console.Read();

        }
    }
}
下面是我的JSON机密的内容和密文

我错过了什么

编辑:好的,我在代码生成请求时中断代码,我可以看到它在头中没有在哪里设置授权令牌承载。为什么?我希望这个HttpClientInitializer类能够解决这个问题,因为API文档说它知道如何处理这个问题,我在internet上找到的每个示例都表明它只是将凭证传递到服务初始值设定项中。但是当我浏览它时,即使凭证已经被授予了访问令牌并且其中存在一个,请求的头也没有更新

我唯一能看到的是,有一种方法可以添加一个HTTP请求拦截器,我可以自己做,但是哇,这看起来真的…奇怪-在他们在dotnet客户端SDK上做了这么多工作之后,老实说,我可以直接编写HTTP API,这样会简单得多,也更容易理解


拼图中缺少的部分是这一行:

ServiceAccountCredential sac = GoogleCredential.FromFile(Secret)
    .CreateScoped(Scopes)
    .UnderlyingCredential as ServiceAccountCredential;
需要对此进行修改:

static string userName = "admin@yourdomain.com" // valid user in your org

ServiceAccountCredential sac = GoogleCredential.FromFile(Secret)
    .CreateScoped(Scopes)
    .CreateWithUser(userName)
    .UnderlyingCredential as ServiceAccountCredential;

Java/Python/Go做类似事情的示例如下:

拼图中缺少的部分是这一行:

ServiceAccountCredential sac = GoogleCredential.FromFile(Secret)
    .CreateScoped(Scopes)
    .UnderlyingCredential as ServiceAccountCredential;
需要对此进行修改:

static string userName = "admin@yourdomain.com" // valid user in your org

ServiceAccountCredential sac = GoogleCredential.FromFile(Secret)
    .CreateScoped(Scopes)
    .CreateWithUser(userName)
    .UnderlyingCredential as ServiceAccountCredential;

Java/Python/Go类似操作的示例如下:

已经回答了这个问题,但在这里添加了更多细节。如果有人想冒充用户使用服务帐户在谷歌硬盘上上传文件。遵循以下步骤

创建服务帐户 为服务帐户启用站点范围的委派 获取服务帐户客户端ID 使用Google管理控制台->管理API启用客户端ID以使用Google驱动器API 使用下面的C代码上传文件

public static DriveService GetService()
{
    string[] scopes = new string[] { DriveService.Scope.Drive };


   //"SERVICE_ACCOUNT_EMAIL_HERE";
    String serviceAccountEmail = "test-417@elated-graph-261115.iam.gserviceaccount.com";

    // Scope and user email id which you want to impersonate
    var initializer = new ServiceAccountCredential.Initializer(serviceAccountEmail)
    {
        Scopes = scopes,
        User = "yourEmail@domain.com"
    };

    //get private key, from .JSON file
    var credential = new ServiceAccountCredential(initializer.FromPrivateKey("-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCkHeAicu6uFQn0\n7KUVTjgZ68nQui8+c8NmKW8aW8vhkBIKfdewXFECiUlTMPyI+HXbubsCK5Dl2xBS\nnphLq6YyE0xEQxNFLYHwfUKuzGQ2rV+qObcZ0mLZjCaf+pw3YiRVuU6OtslLJKJH\n-----END PRIVATE KEY-----\n"));


    // Create the service.
    var service = new DriveService(new BaseClientService.Initializer()
    {
        HttpClientInitializer = credential,
        ApplicationName = "DriveAPI",
    });




    service.HttpClient.Timeout = TimeSpan.FromMinutes(100);
    return service;
}
就这样,我们完成了上面的代码,使用模拟/委派在Google驱动器上使用服务帐户上载文件


参考资料:

已回答此问题,但在此添加更多详细信息。如果有人想冒充用户使用服务帐户在谷歌硬盘上上传文件。遵循以下步骤

创建服务帐户 为服务帐户启用站点范围的委派 获取服务帐户客户端ID 使用Google管理控制台->管理API启用客户端ID以使用Google驱动器API 使用下面的C代码上传文件

public static DriveService GetService()
{
    string[] scopes = new string[] { DriveService.Scope.Drive };


   //"SERVICE_ACCOUNT_EMAIL_HERE";
    String serviceAccountEmail = "test-417@elated-graph-261115.iam.gserviceaccount.com";

    // Scope and user email id which you want to impersonate
    var initializer = new ServiceAccountCredential.Initializer(serviceAccountEmail)
    {
        Scopes = scopes,
        User = "yourEmail@domain.com"
    };

    //get private key, from .JSON file
    var credential = new ServiceAccountCredential(initializer.FromPrivateKey("-----BEGIN PRIVATE KEY-----\nMIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCkHeAicu6uFQn0\n7KUVTjgZ68nQui8+c8NmKW8aW8vhkBIKfdewXFECiUlTMPyI+HXbubsCK5Dl2xBS\nnphLq6YyE0xEQxNFLYHwfUKuzGQ2rV+qObcZ0mLZjCaf+pw3YiRVuU6OtslLJKJH\n-----END PRIVATE KEY-----\n"));


    // Create the service.
    var service = new DriveService(new BaseClientService.Initializer()
    {
        HttpClientInitializer = credential,
        ApplicationName = "DriveAPI",
    });




    service.HttpClient.Timeout = TimeSpan.FromMinutes(100);
    return service;
}
就这样,我们完成了上面的代码,使用模拟/委派在Google驱动器上使用服务帐户上载文件


参考资料:

你表演了吗?是的,我表演了。请看我刚才在下面发布的答案。伙计,这是一次令人沮丧的尝试。你表演了吗?是的,我表演了。请看我刚才在下面发布的答案。伙计,这是一次令人沮丧的努力。