如何使用服务帐户创建 Gmail 委托?

How to create Gmail Delegation with Service Account?

我们过去常常通过 Google 电子邮件设置 API 创建电子邮件委托,但在弃用 OAuth 1.0 之后,我们不再能够正确进行身份验证。在做了一些研究之后,我认为我们应该创建一个服务帐户,为该服务帐户委派域范围的访问权限,然后使用它进行身份验证。但是我似乎无法让它工作,我从 Google 收到的所有信息都是 401 未授权。有人知道我做错了什么吗?这是大部分代码,我正在使用 .Net/c# 并且我正在使用 Google 商业应用程序。

ServiceAccountCredential credential = new ServiceAccountCredential(new ServiceAccountCredential.Initializer("serviceAccountEmail")
                {
                    Scopes = new[] { "https://apps-apis.google.com/a/feeds/emailsettings/2.0/ " },
                    User = "admin email string"
                }.FromCertificate({X509 certificate from service account p12 file}));

credential.RequestAccessTokenAsync(System.Threading.CancellationToken.None).Wait(-1);

GoogleMailSettingsService service = new GoogleMailSettingsService("domain name", "appname");
                service.SetAuthenticationToken(credential.Token.AccessToken);

                service.CreateDelegate("delegator", "delegate");

此操作不需要服务帐户。 Admin SDK 中的电子邮件设置 API 允许超级管理员为域内的帐户设置委派,而无需通过服务帐户模拟用户。

查看 this section of the Developers site for more information on this API. You can also test this on the OAuth Playground 并直接从那里添加代表。

对于那些将来可能需要这个答案的人,我能够通过以下方式提供解决方案。作为参考,我是 运行 一个使用 MVC 框架的 Web 应用程序,但该解决方案也可以针对控制台或 GUI 独立应用程序进行调整。

基本上,我能够使用 GOAuth2RequestFactory 对象验证 GoogleMailSettingsService.Service.RequestFactory

例如:

GoogleMailSettingsService service = new GoogleMailSettingsService("domain", "applicationName");
service.RequestFactory = new GOAuth2RequestFactory("service", "AppName", new OAuth2Parameters() { AccessToken = AuthorizationCodeWebApp.AuthResult.Credential.Token.AccessToken });

现在,对于 AuthorizationCodeWebApp.AuthResult,我执行了以下操作:

public async Task<ActionResult> DelegationMenu(CancellationToken cancellationToken)
{
        var result = await new AuthorizationCodeMvcApp(this, new AppFlowMetadata()).AuthorizeAsync(cancellationToken);

        if (result.Credential == null)
            return new RedirectResult(result.RedirectUri); //Will redirect to login page for Google Admin to authenticate.

        Session["AuthResult"] = result;
        return View();
}

public class AppFlowMetadata : FlowMetadata
{
    private static readonly IAuthorizationCodeFlow flow =
        new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
        {
            ClientSecrets = new ClientSecrets
            {
                ClientId = "ClientId",
                ClientSecret = "ClientSecret"
            },
            Scopes = new[] { "https://apps-apis.google.com/a/feeds/emailsettings/2.0/" },
            DataStore = new FileDataStore("C:\OAuth2.0Tokens")
        });

    public override string GetUserId(Controller controller)
    {
        var user = controller.Session["user"];
        if (user == null)
        {
            user = Guid.NewGuid();
            controller.Session["user"] = user;
        }

        return user.ToString();
    }

    public override IAuthorizationCodeFlow Flow
    {
        get { return flow; }
    }
}