使用自己的 API for web 应用 - 使用 OAuth2 的身份验证过程

Consuming own API for web app - Authentication process with OAuth2

提问人:aborted 提问时间:6/1/2016 最后编辑:Communityaborted 更新时间:6/12/2016 访问量:3426

问:

概述

我目前正在为一个图像共享应用程序创建一个 API,该应用程序将在 Web 上运行,并将在未来的某个时候在移动设备上运行。我了解 API 构建的逻辑部分,但我仍然在努力满足我自己对身份验证部分的要求。

因此,我的 API 必须可供全世界访问:那些具有访客访问权限的人(例如,未登录的人可以上传),以及注册用户。因此,当注册用户上传时,我显然希望用户信息与请求一起发送,并通过数据库中的外键将该用户信息附加到上传的图像上。


通过 OAuth2 进行身份验证 - 实现

我已经知道 OAuth2 是 API 身份验证的必经之路,所以我将实现这个,但我真的很难弄清楚如何处理的情况。我想到使用授权并为我的 Web 应用程序仅生成一组凭据,并让它向 API 发送请求以获取访问令牌并让用户执行操作。用户注册过程本身将由此授权处理。client credentialsclient secret

但是,当用户注册并登录时呢?我现在如何处理身份验证?这需要另一笔赠款来接管吗?我正在考虑在用户登录期间执行一些授权过程,以生成新的访问令牌。这种方法错了吗?


我需要什么帮助

我需要您就如何正确处理我的案例的身份验证流程提供意见。这种双向身份验证过程可能不是我需要的,但这是我理解它的方式。非常感谢您的支持。

身份验证 OAuth-2.0 凭据 API-Design 用户帐户

评论

0赞 MvdD 6/5/2016
您正在为 API 构建什么样的客户端?它是从浏览器调用 API 的 JavaScript 应用程序吗?还是它在服务器上运行?
0赞 aborted 6/5/2016
@MvdD 是的,它将是一个调用 API 的 Javascript Web 应用程序。
0赞 kag0 6/11/2016
@Aborted澄清一下,当您说“我的 Web 应用程序”时,您是在谈论在浏览器中运行的 JavaScript 应用程序?
0赞 aborted 6/11/2016
@kag0 是的,我说的是一个完全用 Javascript 制作的 ReactJS 网站。
0赞 anon 6/14/2019
@Dugi - 只是好奇:你最终使用了什么解决方案?

答:

9赞 iandayman 6/1/2016 #1

你的方法似乎可行。

Oauth2 有 4 个主要部分:

  • 资源服务器(您的 API)Resource Server (your API)
  • 资源所有者(在资源服务器上拥有数据的最终用户)
  • 授权服务器(获取授权并颁发令牌)
  • 客户端(你的 Web 应用 - 以及未来的应用)Client (your web app - and future apps)

请记住,使用客户端凭据授予时,颁发的令牌可能没有任何用户上下文。因此,如果您的 API 端点依赖于令牌中包含的用户标识符/资源所有者,则需要针对此类令牌进行编码。

如果您确实需要令牌来为您的 API 提供一些资源所有者上下文,并且您的 Web 应用程序恰好是您的身份提供商,那么您可以使用资源所有者密码授予,这将在资源所有者/用户的上下文中为您提供令牌和刷新令牌。

授权代码授予是可以的,前提是你未来的 API 使用者是 Web 应用程序(即在服务器上运行)。如果您计划允许移动/本机应用程序使用您的 API,则应考虑在授权服务器中允许式授权。

如果您的 API 没有最终用户,并且每个客户端对 API 的访问权限各不相同,具体取决于它是什么应用,则可以使用 client-credentials 授予和使用范围来限制 API 访问。

编辑

因此,我的 API 必须可以通过访客访问(非 例如,登录的人可以上传)和注册用户。所以 当注册用户上传时,我显然希望该用户被发送 以及请求,并将该用户附加到上传的图像

为此,您的 API 上传终端节点可以处理 Oauth2.0 持有者令牌,但不依赖于它们。例如,端点可以被任何人使用,那些在标头中提供访问令牌的人将把他们的上传与API从令牌中获取的用户上下文相关联。 然后,如果需要,可以使其他终结点依赖于令牌。

根据评论进行编辑

注册过程本身将使用客户端凭据授予, 正确?

我不认为注册过程本身应该成为受 Oauth 保护的资源。理想情况下,注册应由您的身份提供商(例如 google、facebook 或您自己的用户会员数据库)处理。Oauth2.0 的一个优点是,它消除了 API 必须执行用户管理工作的需要。

评论

0赞 aborted 6/3/2016
嘿,谢谢你的回复。我的 API 将具有相当多的端点,这些端点不需要任何用户(他们可以作为访客执行操作),因此在这种情况下,我认为客户端凭据授予可以完成这项工作。但是,当用户注册时(注册过程本身将使用客户端凭据授予,对吗?),那么显然相同的“来宾”操作不得包含用户上下文。这部分让我有点困惑。我该如何解决这个问题?
0赞 Legends 6/9/2016
当令牌保存在 LocalStorage 中以供进一步的 Web API 请求时,如何使用密码授予处理令牌过期?
0赞 iandayman 6/9/2016
密码授予将为您提供访问令牌。该令牌应包含有关问题/到期时间的详细信息,以便你可以计算它是否已过期或接近过期,并且可以使用刷新令牌获取新令牌。
0赞 Legends 6/9/2016
如果我没猜对,我必须在客户端上记住令牌何时过期并接近过期,调用我的 Web 应用,该应用存储了与用户相关的刷新令牌,并且基于此刷新令牌,Web 应用从 OAuth 服务器请求新令牌,然后我的 Web 应用将新令牌发送回用户代理(浏览器)以进行进一步的 Web API 调用, 右?
0赞 iandayman 6/10/2016
@Legends 我建议问一个单独的问题,详细说明您的具体情况。通常,您的 Web 应用不会将令牌发送回浏览器,但需要更多详细信息才能给出正确的答案。
8赞 Juanín 6/10/2016 #2

实际上,您并不需要 oauth 来对自己的 API 进行身份验证。

如果您希望其他应用程序访问您的 API,OAuth2 非常有用。

让我稍微解释一下 OAuth2 是如何工作的:

  • 客户端(应用程序)想要使用您的 API,因此您向他提供客户端凭据(client_token 和 client_secret)。然后,在数据库中设置一组客户端可以使用的重定向位置。
  • 客户需要用户授权才能代表用户使用您的 API。因此,客户端将用户发送到您网站上的 URL(带有客户端需要的client_token范围 [您定义不同范围的含义]、重定向 uri 和response_type [oauth2 定义了不同的response_type但让我们专注于“代码”])
  • 用户登录到您的站点,并接受代表用户授予对客户端的 API 访问权限。当用户接受此授权时,你将生成授权(授权包含用户的信息、请求的凭据 [scope] 以及可以“声明”授予访问权限的客户端)。
  • 然后,用户将被重定向到客户端请求的redirect_uri(当客户端将用户发送到您的身份验证站点时),并在 URL 参数中包含授权代码(它只是一个 ID)。
  • 在此阶段,客户端将向您的 API 发出请求,提供授权代码、他自己的client_token、client_secret和grant_type (authorization_code),他将获得以下响应:authorization_token、refresh_token、token_type(在本例中为 Bearer)、expires_in(过期时间(以秒为单位)和范围。
  • 完成所有这些操作后,客户端将能够使用access_token代表用户向 API 发出请求,直到令牌过期。令牌过期后,客户端必须使用refresh_token(而不是授权代码)请求新的access_token。

评论

0赞 aborted 6/11/2016
我计划将来让我的用户在我的 Web 应用程序上注册应用程序,我知道 OAuth2 是处理这个问题的完美方式。因此,考虑到这一点,我认为从一开始就使用 OAuth2 来验证我自己的应用程序会更明智,因为总有一天我会最终实现它。我的 API 将用 Laravel 编写,我不确定是否可以将多种身份验证方法附加到我的应用程序中,因此我想在一开始就做出正确的选择并长期使用。
0赞 Juanín 6/13/2016
如果您打算让用户在您的 WEB 上注册应用程序,那么您就走在正确的轨道上。我以前从未使用过 Laravel,但我强烈建议您使用第三方库来实现 OAuth2,因为从服务器端实现它非常复杂。
7赞 kag0 6/12/2016 #3

iandayman 的回答有很多很好的信息,但我认为一个更狭窄、更具体的答案可能会对您有所帮助。

因此,对于初学者来说,客户端凭据授予不适合您。如果我们查看 OAuth2 规范,则客户端凭据授予用于

当授权范围为 仅限于客户端控制下的受保护资源...当客户代表自己行事时

这不适合您,原因有两个。
首先,您的客户无法控制任何受保护的资源。您正在访问的所有资源要么不受保护(未登录的人员上传),要么由最终用户控制。此外,您不能在浏览器中保留机密(例如客户端机密);应用程序的任何用户都可以使用浏览器的开发人员工具来查看和破坏机密。
其次,正如我所提到的,客户从不代表自己行事。它始终代表可能已登录也可能未登录的用户执行操作。

您需要资源所有者密码凭据授予
当用户未登录时(就像您提到的上传一样),您只是没有授权。当用户登录时,您可以将其凭据发送到授权服务器。如果密码与用户名匹配,则授权服务器将创建一个令牌,并保留从该令牌到用户的映射,并返回该令牌。然后,每当您的客户端对登录用户发出另一个请求时,您都会将该令牌放在标头中。在后端,您说“如果授权标头中有令牌,请找出它对应的用户,并将其与此上传相关联(或检查是否允许上传)”。
Authorization

用户注册如何进行?很简单,你发布一些用户对象,比如

name: jim beam
username: jimb
password: correct horse battery staple

到您的用户创建终结点(或其他)。生成 salt 并对密码进行哈希处理,然后将用户信息与 salt 和 hash 一起存储在数据库中。此端点上没有任何授权。POST /users

希望这更符合您的要求。

评论

0赞 aborted 6/12/2016
完全没有授权安全吗?这是否有任何潜在的滥用可能性?我的问题可能听起来很荒谬和有趣,但我真的在问是否有可能出错的地方?注册终结点的相同问题。
0赞 kag0 6/12/2016
@Aborted只有对未受保护的资源(任何人都可以做的事情)没有授权才是安全的。这些将是 javascript 应用程序本身、公共配置文件、媒体等。对于受保护的内容(私有映像、修改用户设置等),您需要确保调用端点的人获得授权。不需要控制注册终结点(假设任何人都可以注册)。你在这里的潜在问题是人们使用的公共资源超出了你的处理能力。这些不是严格意义上的安全问题,而是逻辑和扩展问题。
1赞 iandayman 6/12/2016
密码授权仅供你的应用使用,但你不会将此授权类型用于不是由你开发但使用你的 API 的应用。如果您计划公开您的 API,请查看其他授权类型供他们使用。
0赞 anon 6/14/2019
@kag0 - 现在已经过去了几年,您认为 ROPC 仍然是一个不错的选择吗?例如,Identity Server 的一位主要开发人员撰写了这篇文章:scottbrady91.com/OAuth/...
1赞 kag0 6/14/2019
@anon 我同意他在那篇文章中的几乎所有内容。但在这种情况下,ROPC 仍然是正确的赠款。需要理解的一点是,OAuth 是一种授权协议,但问题在于如何在他自己的应用程序上应用它进行身份验证。文章也提到了这一点,“如果您拥有授权服务器和客户端应用程序,那么这是可以原谅的”。我还建议偏离规范并为用户帐户添加 FIDO/U2F/webauthn(这将确保只有您的客户端应用程序才能使用密码凭据)。