# 预认证场景

示例包括 X.509、SiteMinder 和通过运行应用程序的 爪哇 EE 容器进行的身份验证。在使用预身份验证时, Spring 安全性必须

  • 识别提出请求的用户。

  • 为用户获取权限。

细节将取决于外部身份验证机制。在 X.509 的情况下,用户可以通过他们的证书信息来标识,在 SiteMinder 的情况下,用户可以通过 HTTP 请求头来标识。如果依赖于容器身份验证,则将通过在传入的 HTTP 请求上调用getUserPrincipal()方法来识别用户。在某些情况下,外部机制可以为用户提供角色/权限信息,但在另一些情况下,权限必须从单独的来源获得,例如UserDetailsService

# 预认证框架类

因为大多数预身份验证机制遵循相同的模式, Spring Security 有一组类,它们为实现预身份验证的身份验证提供者提供了一个内部框架。这消除了重复,并允许以结构化的方式添加新的实现,而无需从头开始编写所有内容。如果你想使用X.509 认证之类的东西,那么你不需要了解这些类,因为它已经有了一个名称空间配置选项,该选项更易于使用和启动。如果你需要使用显式 Bean 配置,或者正在计划编写自己的实现,那么了解所提供的实现是如何工作的将是有用的。你将在org.springframework.security.web.authentication.preauth下找到类。我们只是在这里提供一个大纲,所以你应该在适当的地方参考 Javadoc 和源代码。

# 抽象预先验证的处理过滤器

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

例 1。覆盖抽象预认证处理过滤器

Java

protected abstract Object getPreAuthenticatedPrincipal(HttpServletRequest request);

protected abstract Object getPreAuthenticatedCredentials(HttpServletRequest request);

Kotlin

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

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

在调用这些之后,筛选器将创建一个PreAuthenticatedAuthenticationToken,其中包含返回的数据,并将其提交以进行身份验证。这里的“身份验证”实际上只是指进一步的处理,以便可能加载用户的权限,但是遵循了标准的安全身份验证体系结构 Spring。

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

# J2EebasedPreAuthenticatedWebAuthenticationDetailsSource

如果筛选器配置了authenticationDetailsSource,这是该类的一个实例,则通过为每个预先确定的“可映射角色”集合调用isUserInRole(String role)方法来获得权限信息。该类从配置的MappableAttributesRetriever获得这些。可能的实现方式包括在应用程序上下文中对列表进行硬编码,并从<security-role>文件中的web.xml信息中读取角色信息。预认证示例应用程序使用后一种方法。

还有一个额外的阶段,其中角色(或属性)使用配置的Attributes2GrantedAuthoritiesMapper映射到 Spring SecurityGrantedAuthority对象。默认值只会将通常的ROLE_前缀添加到名称中,但它使你可以完全控制行为。

# 预先验证 dauthenticationProvider

预先验证的提供者除了为用户加载UserDetails对象外,几乎没有什么可做的。它通过委托给AuthenticationUserDetailsService来实现这一点。后者类似于标准UserDetailsService,但接受一个Authentication对象,而不仅仅是用户名:

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

这个接口可能还有其他用途,但是通过预身份验证,它允许访问打包在Authentication对象中的权限,就像我们在上一节中看到的那样。PreAuthenticatedGrantedAuthoritiesUserDetailsService类实现了这一点。或者,可以通过UserDetailsByNameServiceWrapper实现将其委托给标准UserDetailsService

# HTTP403 禁止 BiddenentryPoint

[AuthenticationEntryPoint](architecture.html# Servlet-authentication-authentryPoint)负责启动未经身份验证的用户的身份验证过程(当他们试图访问受保护的资源时),但在预先验证的情况下,这不适用。如果你 AREN 不将预身份验证与其他身份验证机制结合使用,那么你将仅使用该类的实例来配置ExceptionTranslationFilter。如果用户被AbstractPreAuthenticatedProcessingFilter拒绝,导致空身份验证,则将调用它。如果调用它,它总是返回403-禁止的响应代码。

# 具体实现

X.509 身份验证包含在其自己的章节中。在这里,我们将介绍一些类,它们为其他预先验证的场景提供了支持。

#

外部身份验证系统可以通过在 HTTP 请求上设置特定的头来向应用程序提供信息。一个著名的例子是 SiteMinder,它在一个名为SM_USER的头文件中传递用户名。这个机制得到了RequestHeaderAuthenticationFilter类的支持,它只是从头部提取用户名。默认情况下,它使用SM_USER作为标题名称。有关更多详细信息,请参见 Javadoc。

注意,当使用这样的系统时,框架根本不执行任何身份验证检查,它是极端重要的外部系统已正确配置,并保护了对应用程序的所有访问。
如果攻击者能够伪造其原始请求中的头而不被检测到,那么他们可能会选择他们想要的任何用户名。

# 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>

这里我们假设安全命名空间用于配置。还假定你在配置中添加了UserDetailsService(称为“UserDetailsService”)以加载用户的角色。

# Java EE 容器身份验证

J2eePreAuthenticatedProcessingFilter将从HttpServletRequestuserPrincipal属性中提取用户名。这个过滤器的使用通常与上面J2EebasedPreAuthenticatedWebAuthenticationDetailsSource 中描述的 Java EE 角色的使用相结合。

在 Samples 项目中有一个示例应用程序 (opens new window)使用这种方法,因此,如果你感兴趣的话,可以从 Github 获取代码并查看应用程序上下文文件。

AnonymousJAAS