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 进行权限控制。
默认情况下,SecurityContextHolder 使用 ThreadLocal 来存储这些信息,意味着上下文始终可用在同一执行线程中的方法。例如,获取有关当前用户的信息的方法:
Authentication 定义了 getAuthorities()、getCredentials()、getDetails() 和 getPrincipal() 等接口实现认证功能。
AuthenticationManager 接口是认证相关的核心接口,也是发起认证的入口。但它一般不直接认证,其常用实现类 ProviderManager 内部会维护一个 List<AuthenticationProvider> 列表,其中存放了多种认证方式,默认情况下,只需要通过一个 AuthenticationProvider 的认证就可以被认为登录成功。

图 1 过滤器链的执行流程
Security 本质就是通过一组过滤器来过滤 HTTP 请求,将 HTTP 请求转发到不同的处理模块,最后经过业务逻辑处理返回 Response 的过程。
Security 默认的过滤器的入口在 HttpSecurity 对象中,那么 HttpSecurity 是如何加载的呢?HttpSecurity 对象实际提供的是各个过滤器对应的配置类,通过配置类来控制对应过滤器属性的配置,最后将过滤器加载到 HttpSecurity 的过滤链中。
HttpSecurity 提供的默认过滤器及其配置类如下表所示:
上表提供的默认过滤器并不是在 HttpSecurity 对象初始化的时候就全部加载的,而是根据用户定制情况进行加载。
同时,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 类。该接口定义了如下表所示的方法。接口方法 | 功能说明 |
---|---|
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 用户信息接口定义最详细的用户信息。该接口中的方法如下表所示:接口方法 | 功能说明 |
---|---|
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 提供了多种登录认证的方式,由多种过滤器共同实现,不同的过滤器被加载到应用中,我们可以根据不同的需求自定义登录认证配置。