构建 API 密钥和访问令牌

Architecturing API keys and access tokens

我有一个关于如何使用访问令牌和 API 密钥构建 REST API 的问题。

我有一个 API 需要验证。我想启用两个用例:

  1. 用户使用OAuth2(密码授予)登录界面,并被授予临时访问令牌。此令牌用于对用户进行身份验证。因此,本身使用 API 的 UI 可以获取数据并显示它。

  2. 我还希望用户有一个 API 键来执行相同的调用,但在其应用程序中。显然,与访问令牌相反,我希望 API 密钥长期存在。此外,与绑定给定用户的访问令牌相反(如果我们引入团队机制,每个用户将有不同的访问令牌,尽管他们访问相同的资源),API 键应该是唯一的项目.

虽然相似,但我不确定我应该如何构建它。我认为,在内部,API 密钥和访问令牌都应存储在相同的 table 中,但 API 密钥没有过期时间。我说得对吗?

我不确定的一件事是客户端的概念。似乎在规范中,客户端更像是一个外部应用程序。但是我真的可以在这里使用这个概念吗?

比如每个"project"其实都是不同的客户端(虽然这里的客户端是同一个应用,不是第三方开发者创建的应用)

因此,如果用户 A 在系统上创建一个帐户,将自动创建一个客户端 A,其访问令牌绑定到客户端 A,具有长期访问令牌(又名 API 密钥).例如,这可用于直接对他的代码执行 API 调用。

然后,如果用户 A 登录到仪表板,将创建一个临时访问令牌,但这次没有应用程序,但与用户绑定,生命周期很短。

这听起来合理吗?有没有人已经实现了这样的事情?

谢谢!

我写了一篇 post 关于 RESTful 应用程序使用访问令牌的方法:https://templth.wordpress.com/2015/01/05/implementing-authentication-with-tokens-for-restful-applications/。或许能给点提示。

为了回答您的问题,我认为我们需要一些同质的东西。我的意思是您所有的身份验证机制都应该基于访问令牌。您的 API 密钥将允许您获得一个实际用于身份验证的访问令牌。

据我了解,您的应用程序有两种用户:

  • 最终用户使用 Web UI(通过 OAuth2 使用密码登录)
  • 应用程序(使用 API 键登录)

所以我会实现这两种用户并使他们能够获得访问令牌。在这两种情况下都将使用访问令牌来访问 RESTful 服务。

此外,我认为这个答案可以给你一些其他的提示:Securing my REST API with OAuth while still allowing authentication via third party OAuth providers (using DotNetOpenAuth)

希望它能回答您的问题。 蒂埃里

感谢您的回答。

我实际上对 OAuth2 本身很有经验,我的问题更针对 API 密钥。我喜欢 API 密钥交换访问令牌的想法,但我认为这行不通。 API 密钥是固定的,不会更改,而访问令牌可能会过期。

问题是:应用程序如何知道这是访问令牌还是 API 密钥。我的意思是,好吧,假设在我的数据库中,每个用户在他们的数据库中都有一个 "api_key" 列。

与访问令牌相反,api_key 不会过期(尽管用户最终可以轮换它)。正如我所说,我想要的是身份验证的同构处理。

案例 1:我自己的网络应用 API 调用

工作流程如下,使用OAuth2:

  1. 用户输入他的mail/password。
  2. 授权服务器returns临时访问令牌(例如:"abc")。
  3. 在网络应用程序中,所有 API 调用都是使用此令牌完成的。例如:“/payments/1”授权 header:"Bearer abc".

简洁明了。

情况 2:用户有一个 API 密钥,该密钥不会过期并且可以在他们自己的应用程序中私下使用

显然,授权机制必须保持不变。所以:

  1. 用户进入他的帐户,发现他的 API 密钥是 "def"。
  2. 在他们的服务器代码中,他们可以使用相同的身份验证机制进行相同的调用。所以他可以使用授权调用“/payments/1”:"Bearer def".

而且它必须有效。如您所见,两个示例中都没有任何变化。他们访问相同的资源,相同的授权机制......但在一种情况下我们有一个访问令牌,在另一种情况下我们有一个 API 密钥。而且我不知道我应该如何从数据库的角度和授权代码中实现它。

我的一个潜在想法是使用不同的身份验证机制。对于 OAuth,它将是 "Authorization: Bearer accessToken",而对于 API,它将是基本身份验证:"Authorization: Basic apiKey".

听起来不错吗?

我认为您不应该将 "API keys" 视为访问令牌的替代品。

无论如何您都必须使用访问令牌来承担请求之间的身份验证,因此您实际使用 "API keys" 建模的不是通常的承载令牌的替代品,而是不同的客户端提供其他授权类型来请求令牌。

我个人实施的流程如下:

  1. 用户使用每个用户的通用客户端(即您的 "web app" 客户端,即 public,即它没有 client_secret,使用密码授权类型进行身份验证).
  2. 然后用户可以创建自己的客户端。根据 OAuth2 规范,这些不是 public,因此它们将由 client_idclient_secret 组成。这些就是你所说的 "API keys".
  3. 然后用户将能够通过他们的客户端请求访问令牌,使用您想要支持的任何给定授权类型(例如直接客户端凭据、授权代码、隐式、第三方等)。您将不得不非常强调有关如何处理客户端凭据的适当安全实践。

显然,您必须以客户端可以属于特定用户的方式实现 OAuth2 服务器,并具有不同的可接受授权类型(即您可能不希望允许用户客户端使用密码授权,而您可能希望禁止除您的 Web 应用程序客户端的密码以外的任何授权类型。

然后您将能够在每个客户端或每个授权类型的基础上定义令牌 TTL 或缺少 TTL(例如,通过密码授权请求的访问令牌,仅可由 Web 应用程序客户端使用,将具有较短的 TTL,而授权码授予将提供长期有效的令牌)。
不过,我建议不要完全缺少 TTL,而是使用 refresh_token 授权类型来更新过期的访问令牌。

此外,您可能必须定义某种授权系统(ACL、RBAC 等),以定义哪个客户端可以做什么。这意味着每个访问令牌都应包含对用于创建它的客户端的引用。

所以,总结一下,这里是关系:

用户 有一个 客户.
客户 有一个 用户.
客户端 有很多 Token.
令牌 有一个 客户端.
令牌 有一个 用户

双向 YMMV。

您应该能够使用任何给定平台的最常见 OAuth2 服务器实现来实现我描述的所有内容。

TL;DR:"API keys" 实际上是 OAuth2 客户端