Spring Boot webflux中的线程本地remove()

Posted

技术标签:

【中文标题】Spring Boot webflux中的线程本地remove()【英文标题】:Thread Local remove() in Spring Boot webflux 【发布时间】:2021-12-17 23:10:03 【问题描述】:

我有一个 Web 过滤器,它在 ThreadLocal 属性中设置一个对象,我试图了解应该如何/何时清理这个本地线程 (ThreadLocal.remove()) 以避免异常“用户上下文已启动。”发生这种情况是因为它是从 Spring Boot 线程池中检索到的并设置了以前的值。

我正在使用 Spring Webflux。

我在哪里可以挂钩这个 SecurityAuthorizationContext.clean() 调用?

public class SecurityAuthorizationContext

    private static final ThreadLocal<PrivilegeHolder> userContext = new ThreadLocal<>();

    private final List<String> roles;

    private SecurityAuthorizationContext(List<String> roles)
    
        this.roles = roles;
    

    public static void create(List<String> roles)
    
        if (nonNull(userContext.get()))
        
            log.error("User context already initiated.");
            throw new AuthorizationException("User context already initiated.");
        

        PrivilegeHolder privilegeHolder = new PrivilegeHolder();
        userContext.set(privilegeHolder);

        // example of privileges retrieved from database by the user roles
        privilegeHolder.add(INSERT);
        privilegeHolder.add(DELETE);
    

    public static void clean()
    
        userContext.remove();
    

    public static boolean hasInsertPrivilege()
    
        return userContext.get().hasPrivilege(INSERT);
    

    public static boolean hasDeletePrivilege()
    
        return userContext.get().hasPrivilege(DELETE);
     


public class AuthorizationFilter implements OrderedWebFilter

    private static final String USER_ROLES = "user-roles";

    @Override
    public int getOrder()
    
        return SecurityWebFiltersOrder.AUTHORIZATION.getOrder();
    

    @Override
    public Mono<Void> filter(ServerWebExchange serverWebExchange, WebFilterChain webFilterChain)
    
        ServerHttpRequest request = serverWebExchange.getRequest();
        HttpHeaders headers = request.getHeaders();

        List<String> roles = headers.get(USER_ROLES);

        SecurityAuthorizationContext.create(roles);

        return webFilterChain.filter(serverWebExchange);
            


@Configuration
@EnableWebFluxSecurity
@EnableTransactionManagement
public class ApplicationConfiguration
    
    @Autowired
    private AuthorizationFilter authorizationFilter;

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http)
    
        return http
            .csrf().disable()
            .authorizeExchange()
            .pathMatchers("/**").permitAll()
            .and()
            .addFilterAt(authorizationFilter, AUTHORIZATION)
            .build();
        


更新:长话短说...我只想从请求标头中提取一些内容,并使其可供所有堆栈使用,而不将其作为参数传递。

【问题讨论】:

Webflux 可能会随时切换线程,因此使用线程本地是不安全的,因为线程本地中的信息可能随时丢失。在我看来,您正在尝试实现自定义安全上下文。为什么要实现已经存在的东西 是的,反应流中的线程池把它搞砸了。您在这里重新发明***可能是对的,但我试图了解它在反应性世界中的情况。我只想从请求标头中提取一些内容,并使其可用于所有堆栈而不将其作为参数传递(我更新了引用它的帖子) 然后阅读反应器参考文档。您正在寻找的内容称为“上下文”或“反应式上下文” 【参考方案1】:

所以,最好使用 reactor 上下文而不是 ThreadLocal,您可以在这里阅读:https://projectreactor.io/docs/core/release/reference/#context

【讨论】:

以上是关于Spring Boot webflux中的线程本地remove()的主要内容,如果未能解决你的问题,请参考以下文章

1 个 Spring Boot 应用程序中的 Spring mvc 和 webflux

如何使用 Spring Boot Security 修复 Spring Boot Webflux 应用程序中的“名称为 requestMappingHandlerAdapter 的 bean 定义无效

如何使用 Spring Boot 对 WebFlux 进行异常处理?

带有 Webflux 的 Spring Boot:请求的资源上不存在“Access-Control-Allow-Origin”标头

spring-boot-starter-web 和 spring-boot-starter-webflux 不能一起工作吗?

服务器使用 Spring Boot 和 WebFlux 发送事件