在 C# 中与 Google Admin SDK 集成

Posted

技术标签:

【中文标题】在 C# 中与 Google Admin SDK 集成【英文标题】:Integrating with Google Admin SDK in C# 【发布时间】:2019-09-20 03:37:26 【问题描述】:

我目前正在尝试通过 C# 与 Google Admin SDK 集成,以便我们可以通过自己的系统管理用户。但是,在运行项目时出现错误:未经授权的客户端。

我已经通过超级管理员帐户完成的事情:

设置服务帐号 在服务帐户上启用 GSuite 域范围委派 启用 API 访问 将服务帐户客户端 ID 添加到具有范围 (https://www.googleapis.com/auth/admin.directory.user) 的 API 客户端访问中

这是我正在使用的代码。

ServiceAccountCredential credential = new ServiceAccountCredential(
                new ServiceAccountCredential.Initializer(_googleServiceSettings.Client_Email)
                
                    ProjectId = _googleServiceSettings.Project_Id,
                    User = "superadmin@google.com",
                    Scopes = new[]  DirectoryService.Scope.AdminDirectoryUser 
                .FromPrivateKey(_googleServiceSettings.Private_Key));

            var service = new DirectoryService(new BaseClientService.Initializer
            
                HttpClientInitializer = credential,
                ApplicationName = "Test API"
            );

            var request = service.Users.Get("user@google.com");
            var result = await request.ExecuteAsync();

我得到的完整错误是

执行请求时发生未处理的异常。 Google.Apis.Auth.OAuth2.Responses.TokenResponseException:错误:“unauthorized_client”,描述:“客户端未授权使用此方法检索访问令牌,或客户端未授权任何请求的范围。”,Uri:“”

【问题讨论】:

【参考方案1】:

好的,我已经解决了这个问题。

通过 Google 门户中的安全设置添加以下范围已解决了该问题。这很奇怪,因为他们自己的示例不需要添加此范围,并且他们的文档没有说明此方法需要它。

https://www.googleapis.com/auth/admin.directory.group

【讨论】:

我的示例 + G Suite 不使用 group 范围。你还有其他事情需要group。这个用户有什么不同吗? @JohnHanley - 据我所知,我试图获取的超级管理员或用户没有什么特别之处。我们有多个超级管理员,在他们之间切换没有效果。这同样适用于我正在获取的用户。 我问的是您在 G Suite 中调用“Get()”的用户。例如,此用户是否是某个组的成员?您可以创建一个新用户然后重试吗?除非我故意尝试创建错误,否则我的代码没有问题。但是,我通常会给出所有范围,因此我不必担心委派权限的细节,因为调用者无论如何都必须拥有超级管理员权限。 所以我试图获取的用户与组相关联并且是委派管理员 我在这个问题上花了很多时间。我无法使用需要https://www.googleapis.com/auth/admin.directory.group 的组、权限等在 G Suite 中创建配置。您遗漏了一些有助于确定为什么需要group 的细节。需要它的一个示例是 List() 用户。【参考方案2】:

如果您想使用服务帐户,您可以使用以下代码进行身份验证。

String serviceAccountEmail = "yourserviceaccountmail";
public GmailService GetService(string user_email_address)
    

        var certificate = new X509Certificate2(@"yourkeyfile.p12", 
"notasecret", X509KeyStorageFlags.Exportable);

        ServiceAccountCredential credential = new ServiceAccountCredential(
                   new ServiceAccountCredential.Initializer(serviceAccountEmail)
                   

                       User = user_email_address,
                       Scopes = new[]  GmailService.Scope.MailGoogleCom 
                   .FromCertificate(certificate));

        GmailService service = new GmailService(new BaseClientService.Initializer()
        
            HttpClientInitializer = credential,
            ApplicationName = AppName,
        );

        return service;
    

您可以列出使用此服务的用户。它为我工作。

您可以使用以下代码列出用户列表。 (使用 DirectoryService)

public Users GetDirService()//UserList with DirectoryService
    
        string Admin_Email = "yoursuperadminemail";
        string domain = "yourdomain.com";
        try
        
            var certificate = new X509Certificate2(@"yourkeyfile.p12", "notasecret", X509KeyStorageFlags.Exportable);

            ServiceAccountCredential credentialUsers = new ServiceAccountCredential(
            new ServiceAccountCredential.Initializer(serviceAccountEmail)
            
                Scopes = new[]  DirectoryService.Scope.AdminDirectoryUser ,
                User = Admin_Email,
            .FromCertificate(certificate));

            var serviceUsers = new DirectoryService(new BaseClientService.Initializer()
            
                HttpClientInitializer = credentialUsers,
                ApplicationName = AppName,
            );
            var listReq = serviceUsers.Users.List();
            listReq.Domain = domain;
            Users users = listReq.Execute();
            return users;
        
        catch (Exception ex)
        
            MessageBox.Show("your mail address must be super admin authorized.", "Warning", MessageBoxButton.OK, MessageBoxImage.Warning);
            return null;
        

    

【讨论】:

你能用一个完整的例子改进你的答案吗? 我已经测试了您的示例,但仍然遇到相同的错误。感觉好像我错过了一个设置,但一切看起来都正确设置 也许吧。我在我的项目中使用了这段代码,它显然是有效的。 @Muammer 您能解释一下您在 Google 门户中采取了哪些步骤吗?我已经在我的原始帖子中列出了我已经做过的事情。你做过我没做过的事吗? @niko619 您需要将域范围的权限委托给您的服务帐户。检查here 并转到将域范围的权限委托给您的服务帐户步骤。【参考方案3】:

将打印有关用户的一些信息的示例代码。

重要的是类Google.Apis.Admin.Directory.directory_v1.Data.User

文档link。

您的错误是由于未正确创建凭据造成的。通常,创建凭据时范围存在问题。我假设您为服务帐户正确设置了域范围委派。

我还假设您冒充的用户是 G Suite 超级管理员。如果没有,您将看到 service.Users.Get() 的 403 错误。

文件service_account.json 是您从 Google 控制台下载(或使用 gcloud 创建)的普通 JSON 文件。

user1@example.com 用户是将显示其信息的 G Suite 用户的电子邮件地址。

用户 admin@example.com 是 G Suite 超级管理员。

using Google.Apis.Auth.OAuth2;
using Google.Apis.Admin.Directory.directory_v1;
using Google.Apis.Admin.Directory.directory_v1.Data;
using Google.Apis.Services;
using System;
using System.IO;

// dotnet add package Google.Apis.Admin.Directory.directory_v1
// Tested with version 1.39.0.1505

// Google.Apis.Admin.Directory.directory_v1.Data.User
// https://developers.google.com/resources/api-libraries/documentation/admin/directory_v1/csharp/latest/classGoogle_1_1Apis_1_1Admin_1_1Directory_1_1directory__v1_1_1Data_1_1User.html

namespace Example

    class Program
    
        static void Main(string[] args)
        
            // Service Account with Domain-Wide delegation
            var sa_file = "service_account.json";

            // G Suite User to impersonate
            var user_email = "admin@example.com";

            // G Suite User to get information about
            var gs_email = "user1@example.com";

            // Scopes
            var scopes = "https://www.googleapis.com/auth/admin.directory.user";

            var credential = GoogleCredential.FromFile(sa_file)
                        .CreateScoped(scopes)
                        .CreateWithUser(user_email);

            // Create Directory API service.
            var service = new DirectoryService(new BaseClientService.Initializer()
            
                HttpClientInitializer = credential
            );

            try 
                var request = service.Users.Get(gs_email);

                var result = request.Execute();

                Console.WriteLine("Full Name: 0", result.Name.FullName);
                Console.WriteLine("Email:     0", result.PrimaryEmail);
                Console.WriteLine("ID:        0", result.Id);
                Console.WriteLine("Is Admin:  0", result.IsAdmin);
             catch 
                Console.WriteLine("User not found.");
            
        
    

【讨论】:

我采用了您的示例,但仍然收到相同的消息。 user_email 设置为我们的超级管理员电子邮件。 JSON 文件包含我从控制台获得的服务帐户凭据。不知道在哪里看,因为我已经根据我所看到的设置了所有内容

以上是关于在 C# 中与 Google Admin SDK 集成的主要内容,如果未能解决你的问题,请参考以下文章

C# Google SDK 更新或补丁用户

为 Google Admin SDK 创建和设置自定义属性

如何使用 JWT 通过 NodeJS 客户端库访问 Google Directory (Admin SDK)?

将 Firebase Admin SDK 添加到 Unity 项目

FireBase 消息无法在 OSGI 包中加载 admin_sdk.properties

Firebase Admin SDK、FCM 云消息传递