SPA 和 Spring Boot Rest Api 应用程序中具有授权代码授权类型的 OAuth2 流

Posted

技术标签:

【中文标题】SPA 和 Spring Boot Rest Api 应用程序中具有授权代码授权类型的 OAuth2 流【英文标题】:OAuth2 flow with Authorization Code grant type in SPA and Spring Boot Rest Api application 【发布时间】:2021-09-27 13:33:56 【问题描述】:

我已经阅读了几十篇文章并在 Github 上检查了很多关于授权码授权类型的 OAuth2 的项目,但我仍然认为我对此有一些错误。

我有以下场景展示案例:

前端 SPA 应用(React)

在此应用程序中,用户将使用她的 github 凭据登录,我将列出他的存储库和来自 github 的一些其他信息。

后端Spring Boot:会调用github api并返回响应给fe客户端

我的流程:

1-) 用户点击 github 按钮登录并重定向到 github:https://github.com/login/oauth/authorize?response_type=code&redirect_uri=http:localhost:8080/oauth/callback/github

2-) 用户授权客户端并使用代码重定向到 BE Spring Boot 应用程序。使用此代码,它与访问令牌交换

3-) 在本节中,BE Spring Boot 获取访问令牌并将其发送给 FE React 应用程序

4-) 用于与 github 交互,例如列出存储库和其他操作 FE 将访问令牌发送给 BE,并使用令牌调用 github 并将响应返回给 FE 应用程序

对我来说这是流程,但我对第 3 步和第 4 步有疑问。 FE 需要将访问令牌存储在 cookie 或本地阶段之类的地方,因此它可能不安全。如果我不向 FE 发送访问令牌,BE 如何知道要进行调用的访问令牌,所以此时 Be 必须是无状态的。

我错过了什么?

谢谢。

【问题讨论】:

【参考方案1】:

如果您的 Spring Boot 应用程序是有状态的,您可以将访问令牌保留在后端(例如,在数据库中)并将其绑定到会话 ID。前端客户端将只有一个会话 cookie,并使用该 cookie 调用后端。 Spring 将在 db 中查找 Github 访问令牌并调用 github。

如果您不想拥有数据库,那么唯一的方法是将令牌保存在前端,无论是在 cookie 中还是在内存中。然后将令牌与每个请求一起发送到后端。

我宁愿避免将访问令牌保存在本地存储中——无论是内存还是 http-only cookie。

每种解决方案都有其优点和缺点,并且您必须考虑不同的攻击媒介。例如。当您在后端保留令牌时,您必须更多地考虑 csrf 和会话骑行。

看看我们在 Curity 写的这篇文章,其中概述了一些 best practices for SPAs and OAuth。

【讨论】:

感谢您的回答。我在一篇文章中读到他们将访问和刷新令牌存储在 BE 中(在 DB 中),但将其存储在加密中。然后他们将加密密钥发送到 fe 并将其存储在 cookie 中。每次新请求到达 BE 时,他们从 db 中获取加密的访问令牌,并使用密钥对其进行解密并使用它。您认为这种方法可行吗?你认为它是否能保护我免受 csrf 和会话骑行的影响? 不幸的是,它没有。它可以保护您免受他人阅读 cookie 内容的伤害。因此,即使攻击者设法拦截了此类 cookie,他们也无法从中提取令牌的值并离线使用令牌。他们仍然可以做任何可以用 cookie 完成的事情(所以完全按照用户的方式发送请求)。 Then they send encription key to the fe and store it in cookie - 我认为加密的令牌存储在 cookie 中,而不是加密密钥中。加密密钥应由后端妥善保管,不应向前端发布。 我已经阅读了 Curity 中的部分,但仍然对如何去做感到困惑。您对此有何建议?

以上是关于SPA 和 Spring Boot Rest Api 应用程序中具有授权代码授权类型的 OAuth2 流的主要内容,如果未能解决你的问题,请参考以下文章

使用spring-boot对rest服务进行访问控制

让 oauth2 与 spring-boot 和 rest 一起工作

Spring-Boot REST 服务基本 http 身份验证排除一个端点

spring boot开发REST接口

Spring Boot 2 Rest Api Example

Spring Boot(OAuth2 和 REST):BeanCreationError