Pre-Authentication Scenarios

示例包括 X.509、Siteminder 和应用程序运行所在的 Java EE 容器的身份验证。在使用预身份验证时,Spring Security 必须:

  • 识别提出请求的用户。

  • 获取用户的权限。

详细信息取决于外部身份验证机制。在 X.509 的情况下,可以通过用户证书信息来标识用户,或在 Siteminder 的情况下,可以通过 HTTP 请求头来标识用户。如果依赖容器身份验证,则通过调用传入的 HTTP 请求上的 getUserPrincipal() 方法来标识用户。在某些情况下,外部机制可能会为用户提供角色和权限信息。但是,在其他情况下,您必须从单独的来源(如 UserDetailsService )获取权限。

Pre-Authentication Framework Classes

由于大多数预身份验证机制遵循相同的模式,因此 Spring Security 有一组类,它们提供了一个内部框架用于实现预身份验证验证提供程序。这样消除了重复,并且可以以结构化的方式添加新实现,而无需从头开始编写所有内容。如果你想要使用 X.509 authentication 之类的方法,则无需了解这些类,因为它已经有了更易于使用和上手的命名空间配置选项。如果你需要使用显式 Bean 配置,或者计划编写自己的实现,则需要了解提供的实现是如何工作的。你可以在 org.springframework.security.web.authentication.preauth 下找到这些类。我们在此只提供一个概要,因此你应在适当的情况下查阅 Javadoc 和源代码。

AbstractPreAuthenticatedProcessingFilter

此类检查安全上下文的当前内容,如果它为空,则尝试从 HTTP 请求中提取用户信息并将其提交给 AuthenticationManager 。子类覆盖下列方法来获取此信息。

Override AbstractPreAuthenticatedProcessingFilter
  • Java

  • Kotlin

protected abstract Object getPreAuthenticatedPrincipal(HttpServletRequest request);

protected abstract Object getPreAuthenticatedCredentials(HttpServletRequest request);
protected abstract fun getPreAuthenticatedPrincipal(request: HttpServletRequest): Any?

protected abstract fun getPreAuthenticatedCredentials(request: HttpServletRequest): Any?

调用这些方法后,该过滤器创建包含返回数据的 PreAuthenticatedAuthenticationToken ,并将其提交进行身份验证。在"`authentication`"中,我们的真实意思是进一步处理,以加载用户的权限,但遵循标准的 Spring Security 身份验证架构。

与其他 Spring Security 身份验证过滤器一样,预身份验证过滤器有一个 authenticationDetailsSource 属性,该属性默认创建一个 WebAuthenticationDetails 对象来存储附加信息,例如会话标识符和 details 对象的 Authentication 属性中的原始 IP 地址。在可以从预身份验证机制中获取用户角色信息的情况下,数据也存储在此属性中,其详细信息实现了 GrantedAuthoritiesContainer 接口。这使身份验证提供者能够读取外部分配给用户的权限。接下来,我们来看一个具体的例子。

J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource

如果过滤器配置了此类的实例 authenticationDetailsSource ,则通过为一组预先确定的 “mappable roles” 中的每一个调用 isUserInRole(String role) 方法来获取权限信息。该类从配置的 MappableAttributesRetriever 中获取这些信息。可能的实现包括对应用程序上下文中硬编码一个列表,以及从 <security-role> 文件的 web.xml 信息中读取角色信息。预身份验证示例应用程序使用后一种方法。

有一个附加阶段,其中角色(或属性)通过使用配置的 Attributes2GrantedAuthoritiesMapper 映射到 Spring Security GrantedAuthority 对象。默认情况下,只需将通常的 ROLE_ 前缀添加到名称中,但您可以完全控制行为。

PreAuthenticatedAuthenticationProvider

预身份验证提供程序除了为用户加载 UserDetails 对象外,几乎没有任何其他工作要做。它通过委派给 AuthenticationUserDetailsService 来完成此操作。后者类似于标准的 UserDetailsService ,但使用 Authentication 对象,而不仅仅是用户名:

public interface AuthenticationUserDetailsService {
	UserDetails loadUserDetails(Authentication token) throws UsernameNotFoundException;
}

此接口可能还有其他用途,但是,在预身份验证中,它允许访问封装在 Authentication 对象中的权限,如我们在上一节中看到的。 PreAuthenticatedGrantedAuthoritiesUserDetailsService 类会这样做。或者,它可以通过 UserDetailsByNameServiceWrapper 实现委派给标准的 UserDetailsService

Http403ForbiddenEntryPoint

AuthenticationEntryPoint 负责为未验证用户启动身份验证过程(当他们尝试访问受保护的资源时)。但是,在预身份验证的情况下,这并不适用。如果你不结合其他身份验证机制来使用预身份验证,则只需使用此类的实例配置 ExceptionTranslationFilter。如果 AbstractPreAuthenticatedProcessingFilter 拒绝用户,则调用该方法,从而导致 null 身份验证。如果调用,它总是返回 403- 禁止的响应代码。

Concrete Implementations

X.509 身份验证在其 own chapter 中进行了介绍。在这里,我们来看一些为其他预身份验证场景提供支持的类。

Request-Header Authentication (Siteminder)

外部身份验证系统可以通过在 HTTP 请求中设置特定标题来向应用程序提供信息。一个众所周知的示例是 Siteminder,它在一个名为 SM_USER 的标题中传递用户名。此机制受 RequestHeaderAuthenticationFilter 类的支持,它只从标题中提取用户名。它默认为将标题名称用作 SM_USER 名称。有关更多详细信息,请参阅 Javadoc。

使用这样的系统时,框架根本不执行身份验证检查,并且 extremely 重要的是外部系统已正确配置并保护对应用程序的所有访问。如果攻击者能够在不被检测到的情况下伪造其原始请求中的标题,则他们可能会选择他们想要的任何用户名。

Siteminder Example Configuration

以下示例显示了使用此过滤器的典型配置:

<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”)添加到你的配置中以加载用户角色。

Java EE Container Authentication

J2eePreAuthenticatedProcessingFilter 类从 HttpServletRequestuserPrincipal 属性中提取用户名。该过滤器的使用通常与 Java EE 角色结合使用(如先前的 J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource 中所述)。

有很多 示例应用程序 在代码库中使用了这种方法,因此如果你感兴趣,可以从 Github 中获取代码并查看应用程序上下文文件。