实现预认证

1. 前言

上一节我们讨论了如何保存用户登录状态,本节我们讨论另一个问题,如果无法在 Spring Security 中实现认证,又希望使用 Spring Security 做后续的安全处理该如何实现?

我们知道,Spring Security 既包含认证的标准,也包含鉴权的标准,而鉴权又是认证后续步骤。那如果我们希望 Spring Security 帮我们处理权限,而又希望跳过认证步骤(比如已在外部系统实现认证),这是该如何配置?我们就需要使用「预先认证」解决方案了。

本节,我们重点讨论如何用 Spring Security 实现预先认证效果。

2. 预先认证概述

预先认证的使用场景如:已使用x.509 认证、J2EE 容器等方式通过认证。预认证有两个主要步骤:

  • 识别发起请求的用户身份;
  • 为该用户返回权限。

具体的运行机制与外部认证环境有关。当使用 x.509 证书认证时,用户的识别信息从证书中获取并添加在 Http 请求头中。如果是 J2EE 容器认证,用户的身份信息通过 Http 请求对象的 getUserPrincipal() 方法获得。有时,外部认证系统可以提供用户的身份信息、权限信息,但有时,权限信息要从其他数据源中获取,例如通过 UserDetailsService

3. Spring Security 集成方法

3.1 框架层说明

由于大部分的预先认证模式比较一致,Spring Security 为此提供了一个框架,用来实现预先认证的身份提供器。预先认证模块的实现类均在包 org.springframework.security.web.authentication.preauth 之下。

此处介绍几个核心的成员对象。

3.1.1 AbstractPreAuthenticatedProcessingFilter

该类用来检查当前安全上下文的有效性,如果内容为空,它会尝试从 Http 请求中解析出用户信息,并将其提交到认证管理器 AuthenticationManager。使用该基类需要实现如下两个方法:

  • 获取认证身份信息
protected abstract Object getPreAuthenticatedPrincipal(HttpServletRequest request);
  • 获取认证凭证
protected abstract Object getPreAuthenticatedCredentials(HttpServletRequest request);

通过对这两个方法的调用,该过滤器将创建一个票据对象实例 PreAuthenticatedAuthenticationToken ,该实例包含用户认证结果,并用于认证过程。但是此处的认证过程,仅仅是用来获取权限,只是为了满足标准 Spring Security 流程而实施的步骤。

和其他的安全过滤器类似,预先认证的过滤器包含一个 authenticationDetailsSource 属性,用于保存预先认证流程中的相关数据。

3.1.2 J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource

如果前述过滤器配置了 authenticationDetailsSource,其权限信息可以通过 isUserInRole(String role) 方法判断,角色信息的配置通过 MappableAttributesRetriever 获取,或者通过 <security-role> 标签配置到 web.xml 文件中。

3.1.3 PreAuthenticatedAuthenticationProvider

预先认证身份提供者中的 UserDetails 对象与其他的身份提供者逻辑略有不同,主要体现在获取 Authentication 认证信息时,仅需用户名参数即可。

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

3.1.4 Http403ForbiddenEntryPoint

对 AuthenticationEntryPoint 的配置用对未认证用户来发起认证流程。在预先认证流程中,该配置不起作用,我们只需要配置 ExceptionTranslationFilter 用于处理安全过滤器无法获得用户信息的情形,通常在这种情况下,请求端将收到 403 错误。

3.2 具体实现说明

关于 x.509 认证的集成实现,我们在后续文章中具体说明。

针对 J2EE 容器认证的集成实现,需要指定其 authenticationDetailsSource 对象为 J2eeBasedPreAuthenticatedWebAuthenticationDetailsSource 实例。

4. 小结

本节我们讨论了如何在 Spring Security 中跳过认证过程,使用外部认证结果,本节主要知识点有:

图片描述

  • 预认证是指认证过程被安排在其他程序中完成的认证方式;
  • 预认证是一类认证方式的统称,最常见的预认证方式是 X.509 证书认证;
  • Spring Security 集成预认证相当于让认证过程什么都不执行,只保留鉴别权限的功能。

下节我们讨论如何使用 X.509 证书方式认证。