Google OAuth始终显示同意屏幕

时间:2017-05-19 20:01:23

标签: c++ qt openid-connect google-oauth2 google-openid

我正在构建一个已安装的应用程序,该应用程序将具有使用Qt和C ++的Google Drive REST API功能。我知道Qt现在正在发布支持OAuth流程的新库,但我们假设我是一名学生,并且学习在这一层使用OAuth是该项目的必要条件。

在我的应用程序中,我有一个工作的OAuth流程,用于已安装的应用程序,最后使用QSettings存储访问令牌和刷新令牌(我打开输入是否这也是一个灾难性的坏主意)。该应用程序不需要为自己的缘故/数据进行身份验证/登录,但它需要对Google进行身份验证才能使用访问令牌调用API。此应用程序没有托管相关的Web后端;它很简单,应该可以在本地完全部署(我已经编写并包含一个简单的TCP服务器,它将接收授权redirect_uri,并在从应用程序内部调用时运行和关闭)。

因此,我很好奇最好的方法,以确保当用户打开我的应用程序并想要使用Google云端硬盘功能时,它们会在Google端进行适当的身份验证。比方说,如果我在注册表中维护一个访问令牌,并且这个访问令牌是基于每个用户/每个应用程序授予的(对吗?),那么我怎样才能确保只有令牌所属的用户才能调用用它的API?

这是我的理解和方法;如果我的解释错误,请随时纠正我或教育我。

如果找到访问令牌,请执行以下操作:

  1. 将浏览器页面打开到Google登录域并让用户在那里进行身份验证(这可能会禁止用户使用可以访问其他人无法访问的令牌的缓存登录会话)
  2. 如果用户已使用Google帐户进行了正确的身份验证,请将控制权交还给应用程序,并使用存储的令牌对API进行测试调用。
  3. 如果呼叫失败(以invalid_credentials响应),我应该能够确定它,因为访问令牌已过期,应用程序将通过流程从刷新令牌更新访问令牌。 / LI>

    如果最初未找到访问令牌:

    1. 启动正常的OAuth安装的应用程序流程
    2. 获取令牌并存储它们,以便下次使用前一个程序时用户打开应用程序
    3. 如果找到访问令牌,我的问题是前两个步骤。名义上这可以通过典型的OAuth流来完成,但似乎当使用localhost作为重定向uri时,无论promptaccess_type授权查询参数的设置如何,Google都会始终提示同意。 / p>

      以我的应用程序可以控制的方式完成前两个步骤可以做些什么(即不是依赖于后端服务器托管的解决方案)?

      如果这个问题对于SO的要求过于开放,我可以做出一些限制/假设以限制问题域,但是如果我在不知不觉中阻止了一个好的可行解决方案,我宁愿不这样做。 / p>

      感谢阅读!对不起,如果它是一个冗长的;我想确保我的问题域完全充实!

2 个答案:

答案 0 :(得分:1)

如果您使用的是已安装的应用程序,我建议您不要使用或存储刷新令牌。在客户端存储刷新令牌意味着如果入侵者获得对客户端应用程序的访问权限,他们可以无限制地访问用户的应用程序,而无需输入用户的凭据。如果您坚持使用刷新令牌,请确保使用Google installed app flow,并在请求中包含code_verifier参数。

如果找到访问令牌,您应该try to verify it,如果经过验证,则在google api上使用它,否则强制用户再次登录(如果您选择则刷新它仍然使用刷新令牌。

如果找不到访问令牌,您的流量听起来不错。

关于使用Google登录的一些注意事项:

  1. 如果您在身份验证请求中指定access_type=offline,Google将仅返回刷新令牌。
  2. Google只会在用户的第一个授权请求中返回刷新令牌,除非您始终在查询参数中指定prompt=consent
  3. 根据我的经验,当省略prompt查询参数时,系统不会再次提示用户同意。如果他们登录谷歌,您将获得一个新的访问令牌,但没有刷新令牌,除非您有prompt=consent
  4. 如果您没有使用过您的应用程序的用户记录,我认为您的想法是使用prompt=consent。否则,如果他们之前使用过它,您只需prompt=none
  5. 这只是我对这一切的理解。

答案 1 :(得分:0)

我最终使用的方法只是部署一个将存储在AppData漫游目录中的SQLite数据库。 db模式包括用户名称的字段(来自OpenID IDToken字段,如果存在),用户的图片URL(再次来自IDToken,如果存在),刷新和访问令牌字符串(将当我到处时它被存储为加密字符串),用户的UID /子字符串,以及用户名和密码的字段。

后两个字段是我自己的应用程序中的身份验证字段,我想再次避免,但似乎不可能这样做。因此,系统将提示用户在表单中输入用户名和密码,并将根据前面提到的现有SQLite db文件检查这些凭据。

  • 如果它们存在且正确,则用户登录并可以访问其各自的访问权限和刷新令牌。
  • 如果用户忘记了密码,他们将被要求重新发送(再次通过已安装的应用程序流程),并且在初次登录时提供的任何密码都将用作重置密码。根据我的目的,我认为登录Google以获取已安装的应用流程的证据足以证明用户帐户属于他们,他们应该有权重置密码。
  • 如果用户是新用户并且在本地SQLite数据库文件中没有记录,那么他们也可以单击按钮以“创建新帐户”#34; - 这也有效地完成了授权流程,但这次将一条全新的记录发布到SQLite数据库中,并填写相应的字段。

还有更多可以完成的优化,但至少我越来越接近我想要的Google用户帐户访问权限的安全级别和控制权。

我没有将此标记为答案,因为我觉得这个解决方案仍然不理想,应该有一个更简单的方法。因此,如果某人有证据或经验提供相同级别的身份验证控制而无需维护本地用户帐户数据库,那么我非常乐意将此方法标记为解决方案!

再次感谢!