9

在使用 Spring Boot 编写的 rest API 上使用基于无状态令牌的身份验证时,我看到了一些奇怪的行为。

客户端在每个请求中都包含一个 JWT 令牌,并且我编写的扩展 GenericFilterBean 的自定义过滤器使用以下内容将基于令牌中的声明的身份验证对象添加到安全上下文中:

SecurityContextHolder.getContext().setAuthentication(authentication);

并在处理请求后清除上下文:

SecurityContextHolder.getContext().setAuthentication(null);

但是,当我开发的简单应用程序执行一系列操作时,我有时会发现安全上下文设置不正确 - 有时它对于提供令牌的请求为空。过滤器被正确调用,setAuthencation() 也被调用,但请求身份验证失败,并抛出 403 denied。

如果我通过将会话创建策略设置为 STATELESS 来明确关闭任何 http 会话管理,则此行为将停止。

有什么想法可以在这里发生吗?是否以某种方式在处理请求的线程之间共享安全上下文?

4

1 回答 1

4

根据此处的官方文档,似乎可以共享上下文:http: //docs.spring.io/spring-security/site/docs/3.1.x/reference/springsecurity-single.html

在单个会话中接收并发请求的应用程序中,相同的 SecurityContext 实例将在线程之间共享。即使使用了 ThreadLocal,它也是从每个线程的 HttpSession 中检索到的同一个实例。如果您希望临时更改线程正在运行的上下文,这会产生影响。如果您只使用 SecurityContextHolder.getContext(),并在返回的上下文对象上调用 setAuthentication(anAuthentication),那么 Authentication 对象将在共享相同 SecurityContext 实例的所有并发线程中发生变化。您可以自定义 SecurityContextPersistenceFilter 的行为,为每个请求创建一个全新的 SecurityContext,防止一个线程中的更改影响另一个线程。或者,您可以在临时更改上下文的位置创建一个新实例。SecurityContextHolder.createEmptyContext() 方法总是返回一个新的上下文实例。

于 2015-06-11T13:00:50.350 回答