适用于多个用户的.NET Gmail OAuth2

时间:2016-01-08 16:51:50

标签: gmail gmail-api google-api-dotnet-client

我们正在构建一个解决方案,需要访问我们的客户Gmail帐户才能阅读/发送邮件。在帐户注册时,我们会为客户弹出一个Gmail身份验证页面,然后是后端流程,以便定期阅读他们的电子邮件。

文档似乎并不涵盖此用例。例如https://developers.google.com/api-client-library/dotnet/guide/aaa_oauth表示客户端令牌应该存储在client_secrets.json中 - 如果我们有1000个客户端,那么呢?

服务帐户用于非用户信息,而是用于应用程序数据。此外,如果我使用 GoogleWebAuthorizationBroker 并且用户已删除访问权限或令牌已过期,我也不希望我的后端服务器应用程序弹出一个网络浏览器,因为这似乎可以。

我想我可以使用IMAP / SMTP来实现这一点,但我不认为将这些凭据存储在我的数据库中是个好主意,我也不认为Google也想要这样做。

是否有关于如何实现这一目标的参考?

2 个答案:

答案 0 :(得分:1)

我有同样的情况。我们正在计划用户批准访问权限以代表他们发送电子邮件的功能,但实际发送的消息由非交互式进程执行(在应用程序服务器上运行的计划任务)。

我认为最终的答案是定制的IAuthorizationCodeFlow,它只支持使用现有令牌进行访问,并且不会执行授权过程。我可能会让流模拟用户单击交互式流上的拒绝按钮时发生的响应。也就是说,获得授权令牌的任何需要都只会返回“拒绝”的AuthorizationResult。

我的项目仍在R& D阶段,我甚至还没有进行概念验证。我提供这个答案,希望能帮助其他人制定具体的解决方案。

答案 1 :(得分:0)

虽然@ hurcane的回答很可能是正确的(没有试过),这就是我过去几天的工作。我真的不想从文件中取消/序列化数据以使其工作,所以我有点捣乱了这个解决方案

  1. 获取客户批准的网络应用
    • 使用Google.Apis.Auth.OAuth2.Mvc及文档中的AuthorizationCodeMvcApp
  2. 存储结果访问权限&在DB
  3. 中刷新令牌
  4. 使用AE.Net.Mail通过访问令牌进行初始IMAP访问
  5. 后端还使用AE.Net.Mail进行访问
    • 如果令牌已过期,则使用刷新令牌获取新的访问令牌。
  6. 我没有完成发送部分,但我认为SMTP的工作方式类似。

    该代码基于SO&博客文章:

    t =包含令牌信息的EF对象

    ic = new ImapClient("imap.gmail.com", t.EmailAddress, t.AccessToken, AuthMethods.SaslOAuth, 993, true);
    

    获取更新的Access令牌(需要错误处理)(使用与上面步骤#1相同的API)

    using (var wb = new WebClient())
                {
                    var data = new NameValueCollection();
                    data["refresh_token"] = refresh;
                    data["client_id"] = "(Web app OAuth id)";
                    data["client_secret"] = "(Web app OAuth secret)";
                    data["grant_type"] = "refresh_token";
    
                    var response = wb.UploadValues(@"https://accounts.google.com/o/oauth2/token", "POST", data);
                    string Tokens = System.Text.Encoding.UTF8.GetString(response);
                    var token = Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(Tokens);
                    at = token.access_token;
                    return at;
                }