我开发了一个使用基于令牌的身份验证的无状态REST API,我通过从自定义安全过滤器中调用SecurityContextHolder.getContext().setAuthentication(authentication)
手动将Authentication对象添加到安全上下文。我一直遇到上下文设置不正确的问题我认为是由于这个问题:
Storing the SecurityContext between requests
在一个会话中接收并发请求的应用程序中,将在线程之间共享相同的SecurityContext实例。即使正在使用ThreadLocal,它也是从HttpSession为每个线程检索的相同实例。如果您希望临时更改运行线程的上下文,则会产生影响。如果您只使用SecurityContextHolder.getContext(),并对返回的上下文对象调用setAuthentication(anAuthentication),则Authentication对象将在共享同一SecurityContext实例的所有并发线程中更改。 ...
您可以自定义SecurityContextPersistenceFilter的行为,为每个请求创建一个全新的SecurityContext,防止一个线程中的更改影响另一个请求。
所以问题是 - 你如何改变SecurityContextPersistenceFilter的行为?
我希望安全上下文不与http会话相关联,但不要将会话创建策略设置为无状态,因为我仍然希望实现CSRF保护等。
答案 0 :(得分:1)
今天下午我有一个确切的问题,这个悬而未决的问题与我的搜索完全匹配,所以我想我会补充一点我学到的东西。
我们有正在访问相同SecurityContext的线程。我无法弄清楚如何直接自定义SecurityContextPersistenceFilter的行为(以及按照框架的模式),但是有两种方法可以使它成为线程安全的。
第一个解决方案是确保在我们的主身份验证过滤器中创建一个空上下文。这涵盖了我们所有经过身份验证的请求,因此可以用于我们的解决方案。
SecurityContextHolder.createEmptyContext();
对我有用的第二件事是将WebSecurityConfig更改为无状态,我知道这不适用于OP,但为了完整性起见在此添加了
http.authorizeRequests()
.anyRequest().authenticated()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
...
这两种解决方案都针对我们的特定配置独立工作。我敢肯定,有第三个解决方案会更好看,但是我不知道它是什么,但我想这么做。
这是我第一次发帖。我欢迎任何反馈。