【问题标题】:Authenticating with OAuth2 for an app *and* a website使用 OAuth2 对应用*和*网站进行身份验证
【发布时间】:2012-07-22 20:00:41
【问题描述】:

我正在开发一个主要通过应用访问的网站,我想使用 OAuth2 进行用户注册和身份验证。由于它是一个 Android 应用程序,我将开始使用 Google 的 OAuth2 东西,因为它在 Android 上提供了不错的 UI。

Google 声明 "You can choose to use Google's authentication system as a way to outsource user authentication for your application. This can remove the need to create, maintain, and secure a username and password store." 这是我想要做的。 但是当我浏览他们的所有示例时,我只能找到关于让网站应用针对 Google 服务对用户进行身份验证的内容。

确实,当我使用 Google 的 OAuth2 注册我的应用程序(“客户端”)时,可以选择网站客户端和“已安装”客户端(即移动应用程序),但不能同时使用两者。我可以创建两个单独的客户端,但我阅读了 OAuth2 草案,我认为会有一个问题,我现在将对此进行解释。

这是我设想的工作方式:

  1. 用户要求 MyApp 访问他的私人数据。
  2. 应用使用 Android 的 AccountManager 类为 Google 的 API 请求访问令牌。
  3. Android 对用户说“应用程序 'MyApp' 想要访问您在 Google 上的基本信息。这样可以吗?”
  4. 用户说是。
  5. AccountManager 使用手机上存储的凭据连接到 Google 的 OAuth2 服务器,并要求提供访问令牌。
  6. 返回访问令牌(绿线后面)。
  7. AccountManager 将访问令牌返回给 MyApp。
  8. MyApp 向 MySite 发送请求以获取用户的私人数据,包括访问令牌。
  9. MySite 需要使用访问令牌验证用户。它使用 Google 验证令牌 as described here -“Google,此令牌有效吗?”。
  10. 现在,我想要发生的是 Google 说“是的,给你的确实是那个用户。”,但我认为实际会发生(基于 OAuth2 草案和Google 的文档)是它会说“没门!那个令牌只对 MyApp 有效,而你是 MySite。GTFO!”。

那么我该怎么做呢?请不要说“使用 OpenID”或“不要使用 OAuth2”或其他类似无益的答案。哦,我真的很想继续使用漂亮的AccountManager UI,而不是糟糕的弹出窗口WebViews

编辑

来自 Nikolay 的临时答案(如果它有效,我会报告!)是它应该确实有效,而且 Google 的服务器不会关心访问令牌来自哪里。对我来说似乎有点不安全,但我会看看它是否有效!

更新

我用 Facebook 而不是 Google 实现了这个模式,它完全有效。 OAuth2 服务器不关心访问令牌的来源。至少 Facebook 没有,所以我认为 Google 也没有。

鉴于此,存储访问令牌是一个非常非常糟糕的主意!但我们也不想访问 Facebook/Google 的服务器来检查 每个 请求的身份验证,因为它会减慢一切速度。最好的办法可能是为您的站点添加一个额外的身份验证 cookie,在验证访问令牌时分发该 cookie,但更简单的方法是将访问令牌视为密码并存储它的哈希值。你也不需要加盐,因为访问令牌真的很长。所以上面的步骤变成了这样:

9。 MySite 需要使用访问令牌验证用户。首先,它检查其哈希有效访问令牌的缓存。如果在那里找到令牌的散列,则它知道用户已通过身份验证。否则,它会通过 Google as described here 与 Google 进行检查 - “Google,此令牌有效吗?”。

10。如果 Google 说访问令牌无效,我们会告诉用户 GTFO。否则谷歌会说“是的,这是一个有效的用户”,然后我们检查我们的注册用户数据库。如果找不到该 Google 用户名(或 Facebook id,如果使用 Facebook),我们可以创建一个新用户。然后我们缓存访问令牌的哈希值。

【问题讨论】:

  • 很好奇 - 上述方法最终对你有用吗?
  • 查看更新的问题:它至少对 Facebook 有效。
  • 我也以这种方式实现了它,它正在工作。 Google API、Android 上的 Google Play 服务,以及在我的 Spring3 应用程序的服务器端重用令牌。
  • +1 得到很好解释的问题,包括非常有用的图表。想再给一个 +1 来分享结果...
  • 谢谢。我没有添加的一个更新:facebook 实际上确实建议将访问令牌存储在数据库中,因为您需要它们在 facebook 服务器上执行操作(假设您愿意)。存储密码可能不是一个坏主意,因为如果数据库遭到破坏(并且您意识到),您可以使所有泄露的访问令牌无效。

标签: android oauth oauth-2.0 google-authentication


【解决方案1】:

【讨论】:

    【解决方案2】:

    您可能需要使用 OAuth 令牌进行身份验证的 OpenID Connect。至于AccountManager,当前的OAuth 支持有点老套,新的Google Play Services,即将发布,希望能做得更好。在这里查看demo

    【讨论】:

    • 我看不出 OpenID Connect 演示与我计划中仅使用 OAuth2 有何不同。我的意思是它根本没有提到 OpenID...
    • 你会得到一个登录对话框,你会得到一个令牌,你可以验证 id 并获取用户身份(电子邮件地址等)。第 4 步是第 10 步,但它确实有效:) 此处有关整个想法的详细信息:openid.net/connect 是的,我同意这并不理想,但它是目前最好的(当然,AFAIK)。
    • 哦,对了,你是说我可以按照我的建议去做,而且它真的会起作用吗? Google 的 OAuth2 服务器不会抱怨访问令牌被“窃取”?
    • 没有将它用于真实世界的项目,但是可以。该令牌用于身份验证/用户信息服务,所以没有人应该抱怨:)
    • @NikolayElenkov 您提到的 Google Play 服务的 getToken() 方法的“范围”参数可以使用哪些值?在您的链接oauthssodemo.appspot.com/step/1 中,我看到了有关 OAuth/OpenID 范围的信息,但是当我将这些范围与 Google Play 服务一起使用时,我总是收到“GLS 错误:未知/GoogleAuthException”错误。不幸的是,在 GoogleAuthUtil 类的文档中找不到任何东西。谢谢!
    【解决方案3】:

    至少对于 Google,访问令牌最终会过期。这就是为什么android @987654321@invalidateAuthToken 方法——缓存的访问令牌已经过期,你需要告诉AccountManager 停止给你旧的,而是得到一个新的。这使得缓存令牌更加安全,因为令牌本身不会让您作为该用户永久访问。相反,当它有效时,它只是说“在最近的某个时间点,这个令牌是由一个受信任的来源获得的。”

    以下是我在使用令牌时发现的一些有用的东西。第一个是 Google 的 tokeninfo 端点。令牌本身只是 base64 编码的 JSON。这意味着它没有加密,因此您需要确保使用 HTTPS 进行通信。但是,这也意味着您可以检查令牌并更好地了解正在发生的事情。

    https://www.googleapis.com/oauth2/v1/tokeninfo?id_token=

    如果您的令牌是“abcdef”,您将导航到:

    https://www.googleapis.com/oauth2/v1/tokeninfo?id_token=abcdef

    Google 会为您解包令牌。它是一个简单的 JSON 对象,其中包含一个“expires_in”字段,告诉您令牌仍然有效的秒数。在下面视频中的 6:03,您可以看到解压后的令牌:

    https://developers.google.com/events/io/sessions/383266187

    该视频包含对 OAuth2 的全面概述,如果您要处理 OAuth 和令牌,则非常值得完整观看。演讲者还讨论了其他形式的 Oauth2 令牌,它们不是访问令牌,不会过期。

    另一个有用的资源是 OAuth Playground。这让你可以做一些基本的事情,比如请求范围、组成请求和取回令牌。这个链接似乎偶尔能用,在 Chrome 上我必须安装 Oauth Playground 应用程序:

    https://developers.google.com/oauthplayground/

    这里是视频中的演讲者 Tim Bray 的教程,解释了如何使用访问令牌从 Android 应用程序与服务器进行通信。这对我很有用,因为我开始了解 Google API 控制台中的不同事物如何协同工作:

    http://android-developers.blogspot.in/2013/01/verifying-back-end-calls-from-android.html

    关于您问题的实际答案,我想说您永远不需要在服务器上缓存访问令牌。正如上面的验证来自 Android 的后端调用链接中所解释的,验证令牌几乎总是一个快速的静态调用,这意味着没有理由缓存令牌:

    这些库可以缓存 Google 证书并仅在需要时刷新它们,因此验证(几乎总是)是一个快速的静态调用。

    最后,您确实可以使用AccountManager 来获取访问令牌。但是,Google 现在反而鼓励在 Play Services 库中使用 @987654327@ 类:

    In a nutshell what's the difference from using OAuth2 request getAuthToken and getToken

    请注意蒂姆·布雷(Tim Bray)的评论,他还是来自上述链接的同一个人,他说他们正在努力进入GoogleAuthUtil 路线。但是请注意,这意味着您将仅限于 Google 身份验证。我相信 AccountManager 可以用来获取例如 Facebook 令牌,而不是 GoogleAuthUtil

    【讨论】:

    • 嘿@user1978019,这曾经对我有用,但就在几天前它停止了工作,现在它抛出了这个错误com.google.android.gms.auth.GoogleAuthException: Unknown. 知道为什么吗?我的瞄准镜有问题吗? gist.github.com/lawloretienne/7351151
    • 抱歉 toobsco42,刚看到这个。你解决了吗?
    【解决方案4】:

    我刚刚将an answer 发布到了一个类似的 StackOverflow 问题。

    Google 将其称为 Hybrid Apps,并解释了 "Android app obtains offline access for Web back-end" 的作用。

    它的要点是,您必须将经过按摩的scope 字符串传递给GoogleAuthUtil.getToken,以使其返回授权代码(而不是 OAuth2 令牌)。根据this schematic,该授权码可以从您的移动应用程序传递到您的服务器并交换为 OAuth2 令牌和刷新令牌。

    scope 参数需要如下所示:

    oauth2:server:client_id:<your_server_client_it>:api_scope:<scope_url_1> <scope_url_2> ...
    

    【讨论】:

    • 嘿@Wolfram Arnold,这曾经对我有用,但就在几天前它停止了工作,现在它抛出了这个错误com.google.android.gms.auth.GoogleAuthException: Unknown. 知道为什么吗?我的瞄准镜有问题吗? gist.github.com/lawloretienne/7351151
    • 抱歉,我不确定。我有一段时间没试过这个了。谷歌一定改变了什么:-(
    【解决方案5】:

    您可以在其他任何地方使用移动应用程序检索到的访问令牌。 Drive SDK 有一个漂亮而简单的介绍,贯穿https://developers.google.com/drive/quickstart-android 上的流程

    【讨论】:

      【解决方案6】:

      当我们需要在非谷歌 OAuth 服务器上执行类似操作时,我们将令牌保存在网站上的数据库中。然后,该应用程序将在需要请求数据时使用 Web 服务来请求令牌。

      用户可以在 Web 或应用程序上进行 OAuth 注册。它们共享相同的应用程序令牌,因此它们可以共享相同的访问令牌。注册后,我们会将访问和刷新令牌存储在数据库中,以供任何需要它的应用程序使用。

      【讨论】:

      • “应用程序令牌”是指“客户端 ID”吗?因为据我所知,没有任何方法可以让AccountManager 使用与我的网站相同的客户端 ID。另外,当应用程序向您的网络服务器询问用户的访问令牌时,您如何验证应用程序?干杯。
      • 这是几年前的事了,当时我们使用的是 OAuth 1.0。该系统的设计使用户可以通过网站或移动应用程序在两者中使用相同的应用程序令牌进行身份验证。身份验证后,访问令牌存储在网站后面的数据库中。每当用户登录应用程序(Web 或应用程序)时,都会向数据库(通过应用程序的 Web 服务)请求访问令牌。如果没有访问令牌,则注册流程接管。至于对 Web 服务进行身份验证,我们在 SOAP Web 服务上使用了 WS-Security。
      • 好吧,也许我理解错了,但是如何阻止我的流氓应用程序向您的 Web 服务询问其他人的访问令牌?无论如何,这听起来与我打算做的大致相似,除了我猜现在 OAuth2 由于客户端 ID 的原因是不可能的。我唯一能想到的就是让我的网站假装它也是应用程序。不过看起来很老套。
      • 您需要拥有我的 WS-Security Web 服务标头的证书。如果没有该证书,您将无法调用我的网络服务。
      • 听起来不安全!介意我问一下应用程序/网站的名称吗?你知道,为了……研究……
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-06-24
      • 2010-11-13
      • 2020-01-10
      • 2017-09-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多