跳到主要内容

Spring Integration 中的安全性

QWen Plus 中英对照 Security in Spring Integration

安全是任何现代企业(或云)应用程序中的一个重要功能。此外,对于分布式系统,例如基于企业集成模式构建的系统,安全至关重要。消息独立性和松耦合让目标系统能够相互传递消息,并且消息的 payload 可以包含任何类型的数据。我们既可以信任所有这些消息,也可以保护我们的服务免受“感染性”消息的影响。

备注

从版本 6.3 开始,整个 spring-integration-security 模块已被移除,转而支持更常用的 spring-security-messaging 库所提出的 API。

保护通道

要保护集成流中的消息通道,必须向这些通道添加 AuthorizationChannelInterceptor,或者可以将其配置为带有相应模式的全局通道拦截器:

@Bean
@GlobalChannelInterceptor(patterns = "secured*")
AuthorizationChannelInterceptor authorizationChannelInterceptor() {
return new AuthorizationChannelInterceptor(AuthorityAuthorizationManager.hasAnyRole("ADMIN", "PRESIDENT"));
}
java

有关更多信息,请参阅 全局通道拦截器配置

安全上下文传播

为了确保我们与应用程序的交互是安全的,根据其安全系统规则,我们应该提供一些带有身份验证(主体)对象的安全上下文。Spring Security 项目提供了一种灵活、规范的机制,可以通过 HTTP、WebSocket 或 SOAP 协议对我们的应用程序客户端进行身份验证(也可以通过简单的 Spring Security 扩展为任何其他集成协议实现)。它还提供了一个 SecurityContext,用于对应用程序对象(如消息通道)进行进一步的授权检查。默认情况下,SecurityContext 通过使用 (ThreadLocalSecurityContextHolderStrategy) 与当前线程的执行状态绑定。它通过 AOP(面向切面编程)拦截器在安全方法上被访问,以检查(例如)调用的 principal 是否有足够的权限来调用该方法。这在线程内工作得很好。然而,处理逻辑通常可以在另一个线程上、多个线程上甚至是在外部系统上执行。

标准的线程绑定行为在我们的应用程序基于 Spring Integration 组件及其消息通道构建时很容易配置。在这种情况下,受保护的对象可以是任何服务激活器或转换器,在它们的 <request-handler-advice-chain> 中使用 MethodSecurityInterceptor 进行保护(参见向端点添加行为)或者甚至是 MessageChannel(参见前面的保护通道)。当使用 DirectChannel 通信时,SecurityContext 会自动可用,因为下游流运行在当前线程上。然而,在 QueueChannelExecutorChannel 和带有 ExecutorPublishSubscribeChannel 的情况下,消息由这些通道的性质决定从一个线程转移到另一个(或多个)线程。为了支持这些场景,我们有两种选择:

  • 在消息头中传输 Authentication 对象,并在另一端提取并验证它,然后再进行安全的对象访问。

  • SecurityContext 传播到接收已传输消息的线程。

这在 spring-security-messaging 模块中实现为 org.springframework.security.messaging.context.SecurityContextPropagationChannelInterceptor,可以添加到任何 MessageChannel 或配置为 @GlobalChannelInterceptor。此拦截器的逻辑基于从当前线程(从 preSend() 方法)提取 SecurityContext 并在 postReceive() (beforeHandle()) 方法中填充到另一个线程。有关更多信息,请参阅 SecurityContextPropagationChannelInterceptor 的 Javadoc。

SecurityContext 的传播和填充只是工作的一半。由于消息不是消息流中线程的所有者,而且系统必须确保其对任何传入消息的安全性,因此需要从 ThreadLocal 中清理 SecurityContextSecurityContextPropagationChannelInterceptor 提供了 afterMessageHandled() 拦截器方法的实现。它通过在调用结束时释放线程来清理该传播的主体。这意味着,当处理已移交消息的线程完成消息处理(无论成功与否)时,上下文将被清除,以防止在处理另一条消息时无意中使用它。

备注

在使用 异步网关 时,你应该使用 Spring Security 并发支持 中适当的 AbstractDelegatingSecurityContextSupport 实现,以确保安全上下文在网关调用过程中得以传播。以下示例展示了如何实现:

@Configuration
@EnableIntegration
@IntegrationComponentScan
public class ContextConfiguration {

@Bean
public AsyncTaskExecutor securityContextExecutor() {
return new DelegatingSecurityContextAsyncTaskExecutor(
new SimpleAsyncTaskExecutor());
}

}

@MessagingGateway(asyncExecutor = "securityContextExecutor")
public interface SecuredGateway {

@Gateway(requestChannel = "queueChannel")
Future<String> send(String payload);

}
java