SPA 和 RESTful API 的 OIDC 流程

信息安全 api 开放式连接 单页应用
2021-08-18 21:17:22

我正在构建一个单页应用程序(SPA) 和一个RESTful APIAPI 需要安全性——某些用户只能调用某些端点。我有一个外部身份提供者 (IdP (Okta)),我希望用户使用OpenId Connect协议对其进行身份验证。我试图澄清 SPA 对 RESTful API 的身份验证和授权的正确步骤。我一直在研究的两个流程是授权代码流程和隐式流程。

如果我要使用Implicit flow,那么步骤将是:

  1. 用户访问 SPA,将用户重定向到 IdP 以登录。
  2. 用户登录后,IdP 将用户返回到带有访问令牌和 ID 令牌的 SPA。
  3. (这是我不确定的步骤)每次 SPA 向 RESTful API 发出请求时,它都会将访问令牌和 ID 令牌与请求一起传递,RESTful API 会对其进行验证,然后检查用户是否有权访问特定的端点。如果是,则返回结果,否则用户未经授权。

如果我要使用授权码流程,那么步骤将是:

  1. 与上述步骤 1 相同。
  2. 用户登录后,IdP 将用户返回到带有授权码的 SPA。
  3. (同样,我不确定该步骤是否正确)每次 SPA 向 RESTful API 发出请求时,它都会将授权代码与请求一起传递,然后 RESTful API 与 IdP 交换(连同客户端密码)用于访问令牌和 ID 令牌。它使用这些来检查用户是否可以访问特定的端点。如果是,则返回结果,否则它们是未经授权的。

我认为隐式流程是在这种情况下使用的流程,但是我的步骤正确吗?特别是第 3 步,在每个请求中发送两个令牌,似乎不正确。但我认为我需要两个令牌来验证和确定用户。帮助表示赞赏!

1个回答

这是隐式流和 AuthCode 流之间的区别:

隐式流

注意:自 2019 年 4 月起,Oauth 工作组不再建议在大多数情况下使用隐式流,因为有更好、更安全的方法来完成相同的事情。

  1. 用户导航到 SPA,它将用户重定向到 IdP 以登录。
  2. 用户登录(并授权应用程序,如果需要)。
  3. IdP 使用访问令牌和 ID 令牌将用户返回到 SPA。
  4. SPA 中的 JavaScript 代码将访问令牌和 ID 令牌存储在浏览器中localStorage,并针对它发出的每个请求(通常作为标头)将访问令牌发送到 REST API 服务器。Authorization: Bearer <access token>
  5. 如果需要,REST API 服务器通过与 IdP 交谈来检查访问令牌的有效性。(通常,在 IdP 中签署令牌并验证签名就足够了,实际上不需要通信。)

授权码流程

  1. 用户导航到 SPA,它将用户重定向到 IdP 以登录。
  2. 用户登录(并授权应用程序,如果需要)。
  3. IdP 使用授权码将用户返回到 SPA。
  4. SPA 中的 JavaScript 代码将授权代码发送到loginREST API 服务器上的端点。
  5. REST API 服务器向 IdP 服务器发送一个请求,其中包含授权代码(通常还有一个客户端 ID 和客户端密码,用于向 IdP 服务器标识 REST API 服务器)。
  6. IdP 验证授权代码并将访问令牌和 ID 令牌发送到 REST API 服务器。
  7. REST API Server 将 Access Token 和 ID Token 存储在其内存中,并将其自己的 Session Token 发送回 SPA。
  8. 对于 SPA 向 REST API 服务器发出的每个请求,它都包含 REST API 服务器给它的会话令牌。如果 REST API 服务器需要从另一个服务器请求资源,它会使用存储的访问令牌来发出请求。

您可以从这里看到,AuthCode 流程比隐式流程复杂得多,但好处是访问令牌永远不会存储在用户的控件中。

但是,在这种情况下存储令牌的主要目的不是为了您自己的身份验证,而是为了 REST API Server 需要与其他服务对话的情况,例如 Google、Facebook、Twitter 等。

如果您只使用 OpenID Connect 登录到您自己的 REST API 服务器,但服务器本身不需要使用凭据,那么实现隐式流程要容易得多,而实现 AuthCode 流程实际上并没有为您带来任何好处。