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>
更多信息请参阅全局通道拦截器配置。
安全上下文传播
为了确保我们与应用程序的交互是安全的,并且符合其安全系统规则,我们应该提供一些包含身份验证(principal)对象的安全上下文。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
的 Javadocs。
SecurityContext
的传播和填充只是工作的一半。由于消息不是消息流中线程的所有者,并且系统必须确保其免受任何传入消息的侵害,因此必须从 ThreadLocal
中清理 SecurityContext
。SecurityContextPropagationChannelInterceptor
提供了 afterMessageHandled()
拦截器方法实现。它通过在调用结束时从传播的 principal 中释放线程来执行清理操作。这意味着,当处理移交消息的线程完成消息处理时(无论成功与否),上下文都会被清除,以防止在处理另一条消息时被无意中使用。
当使用异步网关时,您应该使用 Spring Security 并发支持中相应的
|