预认证场景

示例包括 X.509、Siteminder,以及应用程序运行所在的 Java EE 容器提供的认证。在使用预认证时,Spring Security 必须

  • 识别发出请求的用户。

  • 获取用户的权限。

具体细节取决于外部认证机制。在 X.509 的情况下,用户可能通过其证书信息识别;在 Siteminder 的情况下,则通过 HTTP 请求头识别。如果依赖容器认证,则通过调用传入 HTTP 请求上的 getUserPrincipal() 方法来识别用户。在某些情况下,外部机制可能会提供用户的角色和权限信息。然而,在其他情况下,您必须从单独的源(例如 UserDetailsService)获取权限。

预认证框架类

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

AbstractPreAuthenticatedProcessingFilter

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

覆盖 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,并将其提交以进行认证。这里的“认证”实际上只是指进一步的处理,可能用于加载用户的权限,但遵循的是标准的 Spring Security 认证架构。

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

J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource

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

还有一个额外的阶段,通过使用配置的 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 拒绝,导致认证为空,则会调用它。如果被调用,它始终返回 403-forbidden 响应代码。

具体实现

X.509 认证在其单独的章节中有所介绍。在这里,我们介绍一些为其他预认证场景提供支持的类。

请求头认证 (Siteminder)

外部认证系统可以通过在 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 属性中提取用户名。通常将此过滤器与 Java EE 角色的使用结合起来,如前面J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource 中所述。

代码库中有一个使用这种方法的示例应用程序,如果您有兴趣,可以从 Github 获取代码并查看应用程序上下文文件。

© . This site is unofficial and not affiliated with VMware.