首页 > 编程笔记 > Java笔记 阅读:3

Spring Security是什么(非常详细)

安全对于企业来说至关重要,必要的安全认证为企业阻挡了外部非正常的访问,保证了企业内部数据的安全。

当前,数据安全问题越来越受到行业内公司的重视。数据泄漏很大一部分原因是非正常权限访问导致的,于是使用合适的安全框架保护企业服务的安全变得非常紧迫。在 Java 领域,Spring Security 无疑是最佳选择之一。

Spring Security 是 Spring 家族中的一个安全管理框架,能够基于 Spring 的企业应用系统提供声明式的安全访问控制解决方案。它提供了一组可以在 Spring 应用系统中灵活配置的组件,充分利用了 Spring 的 IoC、DI 和 AOP 等特性,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。

虽然,在 Spring Boot 出现之前,Spring Security 已经发展多年,但是使用并不广泛。安全管理这个领域一直是 Shiro 的天下,因为相对于 Shiro,在项目中集成 Spring Security 还是一件麻烦的事情,所以 Spring Security 虽然比 Shiro 强大,但是却没有 Shiro 受欢迎。

随着 Spring Boot 的出现,Spring Boot 对 Spring Security 提供了自动化配置方案,可以零配置使用 Spring Security。这使得 Spring Security 重新焕发新的活力。

Spring Boot 提供了集成 Spring Security 的组件包 spring-boot-starter-security,方便我们在 Spring Boot 项目中使用 Spring Security 进行权限控制。

Security的核心组件

Spring Security 最核心的功能是认证和授权,主要依赖一系列的组件和过滤器相互配合来完成。Spring Security 的核心组件包括 SecurityContextHolder、Authentication、AuthenticationManager、UserDetailsService、UserDetails 等。

1) SecurityContextHolder

SecurityContextHolder 用于存储应用程序安全上下文(Spring Context)的详细信息,如当前操作的用户对象信息、认证状态、角色权限信息等。

默认情况下,SecurityContextHolder 使用 ThreadLocal 来存储这些信息,意味着上下文始终可用在同一执行线程中的方法。例如,获取有关当前用户的信息的方法:
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
    String username = ((UserDetails)principal).getUsername();
} else {
    String username = principal.toString();
}
因为身份信息与线程是绑定的,所以可以在程序的任何地方使用静态方法获取用户信息。例如,获取当前经过身份验证的用户的名称,其中 getAuthentication() 返回认证信息,getPrincipal() 返回身份信息,UserDetails 是对用户信息的封装类。

2) Authentication

Authentication 是认证信息接口,集成了 Principal 类。该接口定义了如下表所示的方法。

表:Authentication 接口定义的方法说明
接口方法 功能说明
getAuthorities() 获取权限信息列表,默认是 GrantedAuthority 接口的一些实现类,通常是代表权限信息的一系列字符串
getCredentials() 获取用户提交的密码凭证,用户输入的密码字符串在认证过后通常会被移除,用于保障安全
getDetails() 获取用户详细信息,用于记录 ip、sessionid、证书序列号等值
getPrincipal() 获取用户身份信息,大部分情况下返回的是 UserDetails 接口的实现类,是框架中常用的接口之一

Authentication 定义了 getAuthorities()、getCredentials()、getDetails() 和 getPrincipal() 等接口实现认证功能。

3) AuthenticationManager

AuthenticationManager 认证管理器负责验证。认证成功后,AuthenticationManager 返回填充了用户认证信息(包括权限信息、身份信息、详细信息等,但密码通常会被移除)的 Authentication 实例,然后将 Authentication 设置到 SecurityContextHolder 容器中。

AuthenticationManager 接口是认证相关的核心接口,也是发起认证的入口。但它一般不直接认证,其常用实现类 ProviderManager 内部会维护一个 List<AuthenticationProvider> 列表,其中存放了多种认证方式,默认情况下,只需要通过一个 AuthenticationProvider 的认证就可以被认为登录成功。

4) UserDetails

UserDetails 用户信息接口定义最详细的用户信息。该接口中的方法如下表所示:

表:UserDetails接口定义的方法说明
接口方法 功能说明
getAuthorities() 获取授予用户的权限
getPassword() 获取用户正确的密码,这个密码在验证时会和 Authentication 中的 getCredentials() 进行比对
getUsername() 获取用于验证的用户名
isAccountNonExpired() 指示用户的账户是否已过期,无法验证过期的用户
isAccountNonLocked() 指示用户的账户是否被锁定,无法验证被锁定的用户
isCredentialsNonExpired() 指示用户的凭证(密码)是否已过期,无法验证凭证过期的用户

5) UserDetailsService

UserDetailsService 负责从特定的地方加载用户信息,通常通过 JdbcDaoImpl 从数据库加载具体实现,也可以通过内存映射 InMemoryDaoImpl 具体实现。

Security验证流程

Security 看起来很复杂,其实一句话就能概述:一组过滤器链组成的权限认证流程。Security 采用的是责任链的设计模式,它有一条很长的过滤器链,整个过滤器链的执行流程如下图所示。


图 1 过滤器链的执行流程

Security 本质就是通过一组过滤器来过滤 HTTP 请求,将 HTTP 请求转发到不同的处理模块,最后经过业务逻辑处理返回 Response 的过程。

Security 默认的过滤器的入口在 HttpSecurity 对象中,那么 HttpSecurity 是如何加载的呢?HttpSecurity 对象实际提供的是各个过滤器对应的配置类,通过配置类来控制对应过滤器属性的配置,最后将过滤器加载到 HttpSecurity 的过滤链中。

HttpSecurity 提供的默认过滤器及其配置类如下表所示:

配置类 过滤器 功能说明
OpenIDLoginConfigurer OpenIDAuthenticationFilter 处理 OpenID 授权请求
HeadersConfigurer HeaderWriterFilter 在返回报文头中添加 Security 相关信息
CorsConfigurer CorsFilter 提供跨域访问配置支持的 Filter
SessionManagementConfigurer SessionManagementFilter 会话管理 Filter
PortMapperConfigurer 用于在 HTTP 及 HTTPS 请求之间重定向时的端口判定
JeeConfigurer J2eePreAuthenticatedProcessingFilter 添加 J2EE 预授权处理机制支持
X509Configurer X509AuthenticationFilter 添加 X509 预授权处理机制支持
RememberMeConfigurer RememberMeAuthenticationFilter 记住用户名及密码功能支持
ExpressionUrlAuthorizationConfigurer FilterSecurityInterceptor Security 的主要 Filter,通过调用权限管理器等进行 HTTP 访问的权限判断
RequestCacheConfigurer RequestCacheAwareFilter 缓存请求,在必要的时候使用缓存的请求
ExceptionHandlingConfigurer ExceptionTranslationFilter 处理 AccessDeniedException 及 AuthenticationException 异常
SecurityContextConfigurer SecurityContextPersistenceFilter SecurityContext 对象持久化 Filter,用于在请求开始阶段初始化并持久化该对象,在后续的 Filter 中可以使用该对象来获取信息
ServletApiConfigurer SecurityContextHolderAwareRequestFilter 在原始请求基础上包装一些方法供后续调用
CsrfConfigurer CsrfFilter 跨站请求伪造保护 Filter
LogoutConfigurer LogoutFilter 退出登录请求处理 Filter
AnonymousConfigurer AnonymousAuthenticationFilter 匿名请求控制 Filter
FormLoginConfigurer UsernamePasswordAuthenticationFilter 表单登录请求处理 Filter
OAuth2LoginConfigurer OAuth2AuthorizationRequestRedirectFilter OAuth2 请求权限控制处理 Filter,为其他网站提供本网站 OAuth2 方式登录,即其他网站通过本网站的账户和密码进行登录授权
ChannelSecurityConfigurer ChannelProcessingFilter 通道选择 Filter,确保请求是通过正确的通道过来的,如 HTTP 或者 HTTPS
HttpBasicConfigurer BasicAuthenticationFilter Security 基础登录授权 Filter,将其结果保存在 SecurityContextHolder 中

上表提供的默认过滤器并不是在 HttpSecurity 对象初始化的时候就全部加载的,而是根据用户定制情况进行加载。

同时,Security 提供了多种登录认证的方式,由多种过滤器共同实现,不同的过滤器被加载到应用中,我们可以根据不同的需求自定义登录认证配置。

相关文章