使用C#控制台应用程序中的服务帐户进行AdminSettings API

时间:2016-03-07 16:12:22

标签: c# oauth google-admin-sdk google-admin-settings-api

我正在尝试将Google Admin Settings API与服务帐户一起使用,但C#控制台应用程序没有成功。

据我所知,我首先得到一个OAuth令牌。我已成功尝试了两种方法:使用Google.Apis.Auth.OAuth2.ServiceAccountCredentials或手动创建JWT断言。

但是当我使用OAuth令牌(例如maximumNumberOfUsers)调用管理员设置API时,我总是会收到403错误,“您无权对域xxx执行操作”消息。

我下载了GAM,因为作者也调用了这个API,因此我可以编写相同的HTTP请求。就像在GAM wiki中解释的那样,我按照所有步骤创建了一个新的服务帐户和一个新的OAuth客户端ID,这样我就可以确定它不是范围问题。我还激活了Jay Lee in this thread提出的调试模式。就像在帖子评论中解释的那样,它仍然无法与我的OAuth令牌一起使用,但是对API的调用会成功使用GAM OAuth令牌。

所以它似乎与OAuth令牌本身有关。我在创建OAuth令牌时遇到的一个问题是我无法指定“sub”属性(或ServiceAccountCredentials的User)。如果我添加它,我会收到403 Forbidden响应“请求的客户端未经授权”。在生成令牌时,即在调用API之前,为error_description。也许这是问题,但我没有看到如何修复它,因为我使用管理员电子邮件。

另一种可能性是此API需要OAuth客户端凭据,因为GAM需要2种不同类型的凭据,即服务帐户和OAuth客户端。因为我只能在我的项目中使用服务帐户凭证,所以如果是这样的话我恐怕会被卡住......

我没有看到其他选项,我两个都坚持,所以任何帮助表示赞赏。谢谢!

我的代码:

public static string GetEnterpriseUsersCount()
{
    string domain = MYDOMAIN;

    string certPath = System.Reflection.Assembly.GetExecutingAssembly().Location;
    certPath = certPath.Substring(0, certPath.LastIndexOf("\\") + 1) + "GAMCreds.p12";

    var certData = File.ReadAllBytes(certPath);
    X509Certificate2 privateCertificate = new X509Certificate2(certData, "notasecret", X509KeyStorageFlags.Exportable);

    ServiceAccountCredential credential = new ServiceAccountCredential(
        new ServiceAccountCredential.Initializer(SERVICE_ACCOUNT_EMAIL)
        {
            Scopes = new[] { "https://apps-apis.google.com/a/feeds/domain/" },
            User = ADMIN_EMAIL
        }.FromCertificate(privateCertificate));

    Task<bool> oAuthRequest = credential.RequestAccessTokenAsync(new CancellationToken());
    oAuthRequest.Wait();


    string uri = string.Format("https://apps-apis.google.com/a/feeds/domain/2.0/{0}/general/maximumNumberOfUsers", domain);

    HttpWebRequest request = WebRequest.Create(uri) as HttpWebRequest;
    if (request != null)
    {
        request.Method = "GET";
        request.Headers.Add("Authorization", string.Format("Bearer {0}", credential.Token.AccessToken));

        // Return the response
        using (WebResponse response = request.GetResponse())
        {
            using (StreamReader sr = new StreamReader(response.GetResponseStream()))
            {
                return sr.ReadToEnd();
            }
        }
    }

    return null;
}

编辑:我专注于下面的Jay Lee建议的范围,看起来缺少的范围是“https://www.googleapis.com/auth/admin.directory.domain”。但是,这无处可写在Admin Settings API文档页面中。至少,我没有找到它。 “https://apps-apis.google.com/a/feeds/domain/”也是必需的,但我已将其添加到允许范围列表中。谢谢Jay!

编辑2:我还更新了源代码,以便将来可以提供帮助。

1 个答案:

答案 0 :(得分:1)

您需要授予您的服务帐户的客户端ID访问管理员设置API的范围。在正确的范围内跟随Drive domain wide delegation instructions除了sub。然后你可以设置sub =而不会出错。