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