对于最新的稳定版本,请使用 Spring Security 7.0.4spring-doc.cadn.net.cn

Run-As 身份验证替换

AbstractSecurityInterceptor 能够在安全对象回调阶段临时替换 Authentication 对象中的 SecurityContextSecurityContextHolder。 仅当原始 Authentication 对象被 AuthenticationManagerAccessDecisionManager 成功处理时,才会发生这种情况。 RunAsManager 指示在 SecurityInterceptorCallback 期间应使用的替代 Authentication 对象(如果有的话)。spring-doc.cadn.net.cn

通过在安全对象回调阶段临时替换Authentication对象,被保护的调用可以调用其他需要不同身份验证和授权凭据的对象。 它还可以针对特定的GrantedAuthority对象执行任何内部安全检查。 由于Spring Security提供了多个辅助类,这些类会根据SecurityContextHolder的内容自动配置远程通信协议,因此这种“以...身份运行”(run-as)替换在调用远程Web服务时特别有用。spring-doc.cadn.net.cn

配置

Spring Security 提供了一个 RunAsManager 接口:spring-doc.cadn.net.cn

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-doc.cadn.net.cn

Spring Security 提供了 RunAsManager 的一个具体实现。 RunAsManagerImpl 类会在任何 ConfigAttributeRUN_AS_ 开头时返回一个替换的 RunAsUserToken。 如果找到任何这样的 ConfigAttribute,替换后的 RunAsUserToken 将包含与原始 Authentication 对象相同的主主体、凭证和授予权限,同时为每个 RUN_AS_ ConfigAttribute 添加一个新的 SimpleGrantedAuthority。 每个新的 SimpleGrantedAuthority 都以 ROLE_ 为前缀,后跟 RUN_AS ConfigAttribute。 例如,RUN_AS_SERVER 会导致替换后的 RunAsUserToken 包含一个 ROLE_RUN_AS_SERVER 授予权限。spring-doc.cadn.net.cn

替换后的 RunAsUserToken 与其他任何 Authentication 对象一样。 它需要由 AuthenticationManager 进行认证,通常是通过委托给合适的 AuthenticationProvider 来完成。 RunAsImplAuthenticationProvider 正是执行此类认证的组件。 它会接受所提交的任何 RunAsUserToken 作为有效Tokens。spring-doc.cadn.net.cn

为防止恶意代码创建一个 RunAsUserToken 并将其提交给 RunAsImplAuthenticationProvider 以确保被无条件接受,所有生成的Tokens中都会存储一个密钥的哈希值。 RunAsManagerImplRunAsImplAuthenticationProvider 在 Bean 上下文中使用相同的密钥进行创建:spring-doc.cadn.net.cn

<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 在创建后是不可变的。spring-doc.cadn.net.cn