如何在私人浏览器会话中询问用户权限?

时间:2016-05-03 14:27:46

标签: c# api google-calendar-api

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

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浏览器,向他询问访问私人日历的权限。 但是,如果在Chrome浏览器中实际连接的Google帐户与通过的电子邮件不同,会发生什么?

如果使用该应用程序的用户使用其他帐户授予访问权限并且他没有注意到这一点,会发生什么?

应用程序将使用不同的帐户上传数据,用户可以认为在个人日历上保留上传数据。在私有浏览器中UserCredential代码阻止之后,有人可以解决这种情况,可能会打开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 即可。混乱。

1 个答案:

答案 0 :(得分:0)

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

通过Basics of Authentication阅读,我们有:

<强> 1。注册您的应用

每个已注册的OAuth应用程序都会分配一个永远不会共享的唯一客户端ID和客户端密钥。注册申请时,您可以填写除授权回调网址之外的所有信息,这也被视为设置申请的最重要部分。它是回调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>

请注意,URL使用范围查询参数来定义应用程序请求的范围。对于示例代码,我们请求user:email范围来阅读电子邮件地址。点击链接后,您将进入授权页面。然后将被重定向到Callback URL中指定的路线。您将获得一个临时代码值,该值将添加到POST HTTP请求中以换取access_token,然后您将能够以已记录的用户身份进行经过身份验证的请求。

# 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

最后,

第3。实施&#34;执行&#34;认证

按照建议:

  

由于我们在会话中持久化范围,因此我们需要在用户检查范围后更新范围时处理案例,或撤消令牌。为此,我们将使用救援块并检查第一个API调用是否成功,这将验证令牌是否仍然有效。之后,我们会检查X-OAuth-Scopes响应标头,以验证用户是否已撤销用户:电子邮件范围。

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