Run-As 身份验证替换
AbstractSecurityInterceptor
能够在安全对象回调阶段临时替换 SecurityContext
和 SecurityContextHolder
中的 Authentication
对象。这仅在原始 Authentication
对象成功通过 AuthenticationManager
和 AccessDecisionManager
处理时才会发生。RunAsManager
指示在 SecurityInterceptorCallback
期间应使用的替代 Authentication
对象(如果有的话)。
通过在安全对象回调阶段临时替换 Authentication
对象,受保护的调用可以调用需要不同身份验证和授权凭据的其他对象。它还可以对特定的 GrantedAuthority
对象执行任何内部安全检查。因为 Spring Security 提供了许多辅助类,这些类会根据 SecurityContextHolder
的内容自动配置远程协议,所以在调用远程 Web 服务时,这些 run-as 替换特别有用。
配置
Spring Security 提供了一个 RunAsManager
接口:
Authentication buildRunAs(Authentication authentication, Object object,
List<ConfigAttribute> config);
boolean supports(ConfigAttribute attribute);
boolean supports(Class clazz);
第一种方法返回的 Authentication
对象应该在方法调用期间替换现有的 Authentication
对象。如果方法返回 null
,则表示不应进行替换。第二种方法由 AbstractSecurityInterceptor
作为其配置属性启动验证的一部分使用。安全拦截器实现会调用 supports(Class)
方法来确保配置的 RunAsManager
支持安全拦截器提供的安全对象类型。
Spring Security 提供了一个 RunAsManager
的具体实现。RunAsManagerImpl
类会在任何 ConfigAttribute
以 RUN_AS_
开头时返回一个替换的 RunAsUserToken
。如果找到任何这样的 ConfigAttribute
,则替换的 RunAsUserToken
包含与原始 Authentication
对象相同的 principal、credentials 和 granted authorities,以及每个 RUN_AS_
ConfigAttribute
的一个新的 SimpleGrantedAuthority
。每个新的 SimpleGrantedAuthority
都以前缀 ROLE_
开始,后面跟着 RUN_AS
ConfigAttribute
。例如,一个 RUN_AS_SERVER
会导致替换的 RunAsUserToken
包含一个 ROLE_RUN_AS_SERVER
的 granted authority。
替换的 RunAsUserToken
就像任何其他 Authentication
对象一样。它需要由 AuthenticationManager
进行认证,可能通过委托给合适的 AuthenticationProvider
来完成。RunAsImplAuthenticationProvider
执行这种认证。它接受任何呈现的 RunAsUserToken
为有效。
为了确保恶意代码不会创建一个 RunAsUserToken
并将其提交给 RunAsImplAuthenticationProvider
以保证被接受,在所有生成的令牌中都存储了一个密钥的哈希值。RunAsManagerImpl
和 RunAsImplAuthenticationProvider
使用相同的密钥在 bean 上下文中创建:
<bean id="runAsManager"
class="org.springframework.security.access.intercept.RunAsManagerImpl">
<property name="key" value="my_run_as_password"/>
</bean>
<bean id="runAsAuthenticationProvider"
class="org.springframework.security.access.intercept.RunAsImplAuthenticationProvider">
<property name="key" value="my_run_as_password"/>
</bean>
通过使用相同的密钥,每个 RunAsUserToken
都可以被验证,因为它是由一个经过批准的 RunAsManagerImpl
创建的。出于安全原因,RunAsUserToken
在创建后是不可变的。