Spring Integration 中的安全性
安全是任何现代企业(或云)应用程序的重要功能之一。此外,对于分布式系统(例如基于企业集成模式构建的系统)而言,安全至关重要。消息独立性和松散耦合使目标系统能够以消息的payload
中的任何类型的数据相互通信。我们可以信任所有这些消息,或者保护我们的服务免受“感染”消息的攻击。
从6.3 版本开始,整个spring-integration-security 模块被移除,取而代之的是更常见的spring-security-messaging 库提出的 API。
|
保护通道
为了保护集成流中的消息通道,必须将AuthorizationChannelInterceptor
添加到这些通道,或者可以将其配置为具有相应模式的全局通道拦截器
-
Java
-
XML
@Bean
@GlobalChannelInterceptor(patterns = "secured*")
AuthorizationChannelInterceptor authorizationChannelInterceptor() {
return new AuthorizationChannelInterceptor(AuthorityAuthorizationManager.hasAnyRole("ADMIN", "PRESIDENT"));
}
<channel-interceptor pattern="securedChannel*">
<beans:bean class="org.springframework.security.messaging.access.intercept.AuthorizationChannelInterceptor">
<beans:constructor-arg>
<beans:bean class="org.springframework.security.authorization.AuthorityAuthorizationManager"
factory-method="hasAnyRole">
<beans:constructor-arg>
<beans:array>
<beans:value>ADMIN</beans:value>
<beans:value>PRESIDENT</beans:value>
</beans:array>
</beans:constructor-arg>
</beans:bean>
</beans:constructor-arg>
</beans:bean>
</channel-interceptor>
有关更多信息,请参见 全局通道拦截器配置。
安全上下文传播
为了确保我们与应用程序的交互是安全的,并符合其安全系统规则,我们应该提供一些安全上下文,其中包含身份验证(主体)对象。Spring Security 项目提供了一种灵活的规范机制,用于通过 HTTP、WebSocket 或 SOAP 协议对我们的应用程序客户端进行身份验证(也可以对任何其他具有简单 Spring Security 扩展的集成协议执行此操作)。它还提供了一个 SecurityContext
,用于对应用程序对象(如消息通道)进行进一步的授权检查。默认情况下,SecurityContext
通过使用(ThreadLocalSecurityContextHolderStrategy
)绑定到当前 Thread
的执行状态。它由安全方法上的 AOP(面向方面编程)拦截器访问,以检查(例如)调用者的 principal
是否具有调用该方法的足够权限。这在当前线程中运行良好。但是,处理逻辑通常可以在另一个线程、多个线程甚至外部系统上执行。
如果我们的应用程序构建在 Spring Integration 组件及其消息通道之上,则标准线程绑定行为很容易配置。在这种情况下,安全对象可以是任何服务激活器或转换器,在它们的 <request-handler-advice-chain>
中使用 MethodSecurityInterceptor
进行保护(请参见 向端点添加行为),甚至可以是 MessageChannel
(请参见前面部分的 保护通道)。在使用 DirectChannel
通信时,SecurityContext
会自动可用,因为下游流在当前线程上运行。但是,在 QueueChannel
、ExecutorChannel
和具有 Executor
的 PublishSubscribeChannel
的情况下,消息会通过这些通道的性质从一个线程转移到另一个线程(或多个线程)。为了支持这些场景,我们有两个选择
-
在消息头中传输
Authentication
对象,并在另一端提取并对其进行身份验证,然后再访问安全对象。 -
将
SecurityContext
传播到接收传输消息的线程。
这在 `spring-security-messaging` 模块中实现为一个 `org.springframework.security.messaging.context.SecurityContextPropagationChannelInterceptor`,可以添加到任何 `MessageChannel` 或配置为 `@GlobalChannelInterceptor`。此拦截器的逻辑基于从当前线程(来自 `preSend()` 方法)提取 `SecurityContext`,并将其填充到 `postReceive()`(`beforeHandle()`)方法中的另一个线程。有关更多信息,请参阅 `SecurityContextPropagationChannelInterceptor` 的 Javadoc 文档。
`SecurityContext` 的传播和填充只是工作的一半。由于消息不是消息流中线程的所有者,并且系统应该确保它免受任何传入消息的攻击,因此必须从 `ThreadLocal` 中清除 `SecurityContext`。`SecurityContextPropagationChannelInterceptor` 提供了 `afterMessageHandled()` 拦截器方法实现。它通过在调用结束时从传播的 principal 中释放线程来清理操作。这意味着,当处理传递消息的线程完成处理消息(成功或失败)时,上下文将被清除,因此它不会在处理另一条消息时被无意中使用。
当使用 异步网关 时,您应该使用 Spring Security 并发支持 中的适当 `AbstractDelegatingSecurityContextSupport` 实现,以确保安全上下文传播在网关调用中进行。以下示例展示了如何做到这一点
|