1. 概述
在传统的Web应用程序中,登录通常需要将用户名和密码发送到服务器进行身份验证。虽然这些元素理论上可以是 GET 请求中的 URL 参数,但将它们封装到 POST 请求中显然要好得多。
但是,由于不需要发送任何敏感信息,是否可以通过 GET 请求进行注销?
在本教程中,我们将了解此设计考虑的各个方面。
2. 服务器端会话
当我们管理服务器端会话时,我们必须公开一个端点来销毁这些会话。由于 GET 方法简单,我们可能会想使用它。当然,这在技术上是可行的,但可能会导致一些不良行为。
有一些进程(例如Web 加速器)将为用户预取 GET 链接。预取的目的是当用户点击该链接时立即提供内容,从而减少页面加载时间。这些过程假设GET 链接严格用于返回内容,而不是用于更改任何内容的状态。
如果我们将注销公开为 GET 请求并将其呈现为链接,则这些进程可能会在尝试预取页面上的链接时无意中注销用户。
如果我们的注销 URL 不是静态可用的(例如由 javascript 确定),这可能不是问题。然而, HTTP/1.1 RFC明确规定 GET 方法只能用于返回内容,用户不能对 GET 请求的任何副作用负责。我们应该尽可能遵循这一建议。
相反,RFC 将 POST 方法描述为一种可以将数据(我们的会话或会话 ID)提交到数据处理进程(注销)的方法。这是对我们正在努力实现的目标的更恰当的描述。
2.1.春季安全
默认情况下,Spring Security 要求注销请求的类型为 POST。但是,当我们禁用CSRF 保护时,我们可以使 Spring 使用 GET 注销请求:
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
...
}
3.无状态REST
当我们管理无状态 REST 会话时,“注销”的概念发生了变化。在无状态环境中,每个请求都包含整个会话。因此,可以通过简单地使用 Javascript 丢弃会话而不是发送任何类型的请求来“注销”。
但是,出于安全原因,仍应向服务器通知注销操作,以便将已撤销的 JWT 列入黑名单。这可以防止“注销”后使用会话。
即使在无状态环境中,我们仍然必须在注销时向服务器发送请求。 由于此类请求的目的不是检索内容,因此不应通过 GET 进行。相反,应该将会话 POST 到服务器并明确注销意图。
4。结论
在这个简短的讨论中,我们简要讨论了注销应该是 GET 还是 POST 的常见设计问题。
我们考虑了这个问题的各个方面:
- 从语义上讲,GET 请求不应该有任何有状态的副作用
- 用户可能在浏览器中运行一些包含预取链接的进程。如果通过 GET 进行注销,则预取过程可能会在登录后无意中将用户注销
- 即使无状态会话也应该向服务器报告注销事件,这应该通过 POST 请求来完成