C# 如何在专用浏览器会话中请求用户权限?

C# 如何在专用浏览器会话中请求用户权限?,c#,api,google-calendar-api,C#,Api,Google Calendar Api,我注意到在googleoauth2上出现了一个非常令人沮丧的情况,其中传递的电子邮件与实际连接到系统的帐户不同。让我更好地解释一下,我写了这个方法,要求用户允许访问我的应用程序到用户私有的谷歌日历: public static CalendarService OAuth(string userName) { string[] scopes = new string[] { CalendarService.Scope.Calendar, Cale

我注意到在
googleoauth2
上出现了一个非常令人沮丧的情况,其中传递的电子邮件与实际连接到系统的帐户不同。让我更好地解释一下,我写了这个方法,要求用户允许访问我的应用程序到用户私有的谷歌日历:

public static CalendarService OAuth(string userName)
{
    string[] scopes = new string[]
    {
         CalendarService.Scope.Calendar,
         CalendarService.Scope.CalendarReadonly
    };

    try
    {
        UserCredential credential = GoogleWebAuthorizationBroker.AuthorizeAsync(new ClientSecrets
        {
             ClientId = "client id Google Developer Console",
             ClientSecret = "Secret key Google Developer Console"
        },
        scopes,
        userName,
        CancellationToken.None,
        new FileDataStore("Stored.Token")).Result;

        CalendarService service = new CalendarService(new BaseClientService.Initializer()
        {
              HttpClientInitializer = credential,
              ApplicationName = "Application name"
        });
      return service;
     }
     catch (Exception ex)
     {
          Console.WriteLine(ex.InnerException);
          return null;
     }
 } 
现在有人已经了解了情况,但我想解释一下为什么这个程序对我不好。假设我想创建一个应用程序,当第一个屏幕允许用户插入个人电子邮件时,此电子邮件应通过方法
OAuth
作为参数
userName
在Google浏览器窗口上请求用户权限

在这里没有问题之前,用户已经输入了电子邮件,并且应用程序打开谷歌浏览器,向他请求访问私人日历的权限。 但是,如果在
Chrome
浏览器中实际连接的谷歌帐户与传递的电子邮件不同,会发生什么

如果使用该应用程序的用户使用不同的连接帐户授予访问权限,而他没有注意到这一点,会发生什么

应用程序将使用一个不同的帐户来上传数据,用户可以将数据上传到个人日历上。有人已经解决了这种情况,可能在私人浏览器中的
UserCredential
code块之后打开Chrome,如果是,在这种情况下,令牌将存储在指定的文件夹中:
AppData\Roaming\stored.token

实践示例:

1。我的应用程序中的用户类型私人电子邮件:
foo@gmail.com

2。应用程序启动Chrome会话并询问用户权限,帐户已连接
bar@gmail.com

3。用户没有注意到这种情况,并授予我的应用访问
bar@gmail.com

4。我的应用程序将使用
bar@gmail.com
用于上传事件,但用户认为应用程序仍在使用
foo@gmail.com


5。混乱。

可以通过执行OAuth流并使用授予的令牌和作用域更新私有浏览器会话来防止不同帐户的使用

通读全文,我们有:

1。注册你的应用程序

每个已注册的OAuth应用程序都被分配了一个唯一的客户端ID和客户端机密,永远不应该共享。注册应用程序时,您可以填写除授权回调URL之外的所有信息,这也是设置应用程序最重要的部分。它是一个回调URL,用户在成功身份验证后将在其中重定向

2。接受用户授权

客户端ID和客户端密钥来自应用程序的配置页面,建议将其存储为环境变量,如示例代码所示

<html>
  <head>
  </head>
  <body>
    <p>
      Well, hello there!
    </p>
    <p>
      We're going to now talk to the GitHub API. Ready?
      <a href="https://github.com/login/oauth/authorize?scope=user:email&client_id=<%= client_id %>">Click here</a> to begin!</a>
    </p>
    <p>
      If that link doesn't work, remember to provide your own <a href="/v3/oauth/#web-application-flow">Client ID</a>!
    </p>
  </body>
</html>
最后

3。实施“持久”身份验证

根据建议:

因为我们在会话中持久化作用域,所以当用户在检查作用域后更新它们,或者撤销令牌时,我们需要处理这些情况。为此,我们将使用一个rescue块并检查第一个API调用是否成功,这将验证令牌是否仍然有效。之后,我们将检查X-OAuth-Scopes响应头,以验证用户没有撤销user:email范围


通过实现developer github中显示的代码,我们现在有了
authenticated
方法来检查用户是否已经过身份验证。如果没有,则调用
authenticate
方法,该方法执行OAuth流,并使用授予的令牌和作用域更新会话。

您的答案如何解决此问题?我认为这不能由用户修复,因为谷歌应该更改.NET DLL,所以在请求许可之前实现帐户选择。我做了一些研究,但没有找到任何解决办法。建议ILDRUGO打开浏览器的私有会话的解决方案可能是一种解决方案,但您必须考虑以下事项:1。私有会话以某种方式允许您获取访问令牌?2.如何告诉API在代码后面打开一个私有会话?3.不知何故,这是否符合谷歌的许可条款?
# fetch user information
auth_result = JSON.parse(RestClient.get('https://api.github.com/user',
                                        {:params => {:access_token => access_token}}))

# if the user authorized it, fetch private emails
if has_user_email_scope
  auth_result['private_emails'] =
    JSON.parse(RestClient.get('https://api.github.com/user/emails',
                              {:params => {:access_token => access_token}}))
end

erb :basic, :locals => auth_result