On this page
28. Pre-Authentication Scenarios
在某些情况下,您想使用 Spring Security 进行授权,但是在访问应用程序之前,某些外部系统已经对用户进行了可靠的身份验证。我们将这些情况称为“预身份验证”方案。示例包括 X.509,Siteminder 以及通过运行应用程序的 Java EE 容器进行的身份验证。使用预认证时,Spring Security 必须
标识发出请求的用户。
获取用户的权限。
详细信息将取决于外部身份验证机制。在 X.509 中,可以通过其证书信息来标识用户;在 Siteminder 中,可以通过 HTTP 请求 Headers 来标识用户。如果依赖于容器身份验证,将通过对传入的 HTTP 请求调用getUserPrincipal()
方法来标识用户。在某些情况下,外部机制可能会为用户提供角色/权限信息,但在其他情况下,必须从单独的来源(例如UserDetailsService
)获得权限。
28.1 预身份验证框架类
因为大多数预认证机制遵循相同的模式,所以 Spring Security 具有一组类,这些类提供了用于实现预认证的认证提供程序的内部框架。这消除了重复,并允许以结构化的方式添加新的实现,而不必从头开始编写所有内容。如果您想使用X.509 authentication之类的内容,则无需了解这些类,因为它已经具有一个名称空间配置选项,该选项更易于使用和入门。如果您需要使用显式的 Bean 配置或计划编写自己的实现,那么对所提供的实现如何工作的理解将非常有用。您将在org.springframework.security.web.authentication.preauth
下找到类。我们仅在此处提供概述,因此您应该在适当的地方查阅 Javadoc 和源代码。
28.1.1 AbstractPreAuthenticatedProcessingFilter
此类将检查安全性上下文的当前内容,如果为空,它将尝试从 HTTP 请求中提取用户信息并将其提交给AuthenticationManager
。子类重写以下方法来获取此信息:
protected abstract Object getPreAuthenticatedPrincipal(HttpServletRequest request);
protected abstract Object getPreAuthenticatedCredentials(HttpServletRequest request);
调用完这些之后,过滤器将创建一个包含返回数据的PreAuthenticatedAuthenticationToken
并将其提交以进行身份验证。这里的“身份验证”实际上只是意味着进一步处理以加载用户的权限,但是遵循标准的 Spring Security 身份验证体系结构。
像其他 Spring Security 身份验证过滤器一样,预身份验证过滤器具有authenticationDetailsSource
属性,默认情况下会创建WebAuthenticationDetails
对象,以在Authentication
对象的details
属性中存储其他信息,例如会话标识符和始发 IP 地址。如果可以从预身份验证机制获取用户角色信息,则数据也存储在此属性中,详细信息实现GrantedAuthoritiesContainer
接口。这使身份验证提供程序可以读取从外部分配给用户的权限。接下来,我们将看一个具体示例。
J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource
如果过滤器配置有authenticationDetailsSource
作为此类的实例,则通过为“Map 角色”的每个 sched 集合调用isUserInRole(String role)
方法来获取权限信息。该类从已配置的MappableAttributesRetriever
中获取它们。可能的实现包括在应用程序上下文中对列表进行硬编码,以及从web.xml
文件中的<security-role>
信息中读取角色信息。预认证示例应用程序使用后一种方法。
在另一个阶段,使用已配置的Attributes2GrantedAuthoritiesMapper
将角色(或属性)Map 到 Spring Security GrantedAuthority
对象。默认值只是在名称中添加通常的ROLE_
前缀,但它使您可以完全控制行为。
28.1.2 PreAuthenticatedAuthenticationProvider
经过预身份验证的提供程序除了为用户加载UserDetails
对象外,无所要做。它通过委派AuthenticationUserDetailsService
来实现。后者与标准UserDetailsService
类似,但采用Authentication
对象,而不仅仅是用户名:
public interface AuthenticationUserDetailsService {
UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException;
}
该接口可能还有其他用途,但具有预身份验证功能,它允许访问打包在Authentication
对象中的授权机构,如上一节所述。 PreAuthenticatedGrantedAuthoritiesUserDetailsService
类可以执行此操作。或者,它可以通过UserDetailsByNameServiceWrapper
实现委派给标准UserDetailsService
。
28.1.3 Http403ForbiddenEntryPoint
technical overview章节讨论了AuthenticationEntryPoint
。通常,它负责启动未经身份验证的用户的身份验证过程(当他们尝试访问受保护的资源时),但是在经过预先身份验证的情况下,这并不适用。如果您未将预身份验证与其他身份验证机制结合使用,则只能使用此类的实例配置ExceptionTranslationFilter
。如果用户被AbstractPreAuthenticatedProcessingFilter
拒绝而导致身份验证为空,则将调用此方法。如果被调用,它将始终返回403
禁止响应代码。
28.2 具体实施
X.509 身份验证包含在其own chapter中。在这里,我们将看一些为其他预身份验证的场景提供支持的类。
28.2.1 请求 Headers 身份验证(Siteminder)
外部身份验证系统可以通过在 HTTP 请求上设置特定的 Headers 来向应用程序提供信息。一个著名的例子是 Siteminder,它在名为SM_USER
的 Headers 中传递用户名。 RequestHeaderAuthenticationFilter
类支持此机制,该类仅从 Headers 中提取用户名。默认情况下,使用名称SM_USER
作为标题名称。有关更多详细信息,请参见 Javadoc。
Tip
请注意,当使用这样的系统时,框架完全不执行身份验证检查,因此,正确配置外部系统并保护对应用程序的所有访问非常重要。如果攻击者能够在不检测到原始请求的情况下伪造 Headers,则他们可能会选择所需的任何用户名。
Siteminder 示例配置
使用此过滤器的典型配置如下所示:
<security:http>
<!-- Additional http configuration omitted -->
<security:custom-filter position="PRE_AUTH_FILTER" ref="siteminderFilter" />
</security:http>
<bean id="siteminderFilter" class="org.springframework.security.web.authentication.preauth.RequestHeaderAuthenticationFilter">
<property name="principalRequestHeader" value="SM_USER"/>
<property name="authenticationManager" ref="authenticationManager" />
</bean>
<bean id="preauthAuthProvider" class="org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationProvider">
<property name="preAuthenticatedUserDetailsService">
<bean id="userDetailsServiceWrapper"
class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<property name="userDetailsService" ref="userDetailsService"/>
</bean>
</property>
</bean>
<security:authentication-manager alias="authenticationManager">
<security:authentication-provider ref="preauthAuthProvider" />
</security:authentication-manager>
我们在这里假设security namespace用于配置。还假定您已在配置中添加了UserDetailsService
(称为“ userDetailsService”)以加载用户的角色。
28.2.2 Java EE 容器身份验证
J2eePreAuthenticatedProcessingFilter
类将从HttpServletRequest
的userPrincipal
属性中提取用户名。通常将此过滤器与名为“ J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource”的部分中所述的 Java EE 角色结合使用。
代码库中有一个使用此方法的示例应用程序,因此,如果有兴趣,可以从 github 上获取代码,并查看应用程序上下文文件。该代码位于samples/xml/preauth
目录中。