gpt4 book ai didi

java - SecurityContext#setAuthentication 是否保证可见性?

转载 作者:IT老高 更新时间:2023-10-28 20:42:14 27 4
gpt4 key购买 nike

我在我的项目中使用 Spring Security。

我有更改登录的功能。为了实现这个目标,我使用以下代码

Authentication authentication = ...
SecurityContextHolder.getContext().setAuthentication(authentication);

但现在我正在详细研究这段代码,发现身份验证字段不是 volatile 因此可见性保证:

 public class SecurityContextImpl implements SecurityContext {

private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

// ~ Instance fields
// ================================================================================================

private Authentication authentication;

我应该用我自己的同步来包装我的代码以实现可见性吗?

附言

我已阅读 https://stackoverflow.com/a/30781541/2674303

In an application which receives concurrent requests in a single session, the same SecurityContext instance will be shared between threads. Even though a ThreadLocal is being used, it is the same instance that is retrieved from the HttpSession for each thread. This has implications if you wish to temporarily change the context under which a thread is running. If you just use SecurityContextHolder.getContext(), and call setAuthentication(anAuthentication) on the returned context object, then the Authentication object will change in all concurrent threads which share the same SecurityContext instance. You can customize the behaviour of SecurityContextPersistenceFilter to create a completely new SecurityContext for each request, preventing changes in one thread from affecting another. Alternatively you can create a new instance just at the point where you temporarily change the context. The method SecurityContextHolder.createEmptyContext() always returns a new context instance.

但我不明白 spring 如何保证可见性。刚刚写到 session 中的每个线程都会看到变化。但没有答案有多快?更重要的是 - 没有解释可见性机制

最佳答案

您的怀疑是有道理的,可见性不是保证。当所有 ThreadLocalMap 的条目都存储同一个对象时,ThreadLocal 不是线程安全的。

引用文档部分,Storing the SecurityContext between requests , 就这一事实向您发出警告并提出可能的解决方案,以一种防止影响其他线程的方式更改上下文。

这种解决方案的一个例子是 RunAs mechanism ,这会在安全对象回调阶段更改上下文。

但是,据我了解,您需要“即时”更改用户的登录名(即用户名)。如果我是对的,那么问题是,当您设置修改后的 Authentication - 另一个线程可以读取旧值。为了避免这种竞态条件,你需要登录写 happens-before 每次连续登录读取。

Authentication接口(interface)有getPrincipal()方法,它返回一个 Object,它是一个 UserDetails实例(在大多数情况下)。该对象通常用于获取当前(经过身份验证的)用户的用户名。

因此,如果您想“即时”更改经过身份验证的用户的登录名,您可以修改此 UserDetails 对象中的 username 属性。

以线程安全的方式实现它的可能方法是使用 volatile String username 属性的自定义 UserDetails 实现(默认 User 实现具有不可变的用户名) .

您还应该创建一个 UserDetailsService 并将其连接到您的配置中。实现,它将使用您的自定义 UserDetails

关于java - SecurityContext#setAuthentication 是否保证可见性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46302894/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com