跳至主要內容

Servlet应用

zzz大约 7 分钟后端SpringSpring Security

Servlet应用

spring-security文档open in new window 调试环境为spring-boot:2.1.4 + spring-security:5.1.10 + spring-security-oauth2:2.3.5的项目环境

SpringBoot自动配置

Spring Boot 自动做以下事情:

  • 开启Spring Security的默认配置,创建名为springSecurityFilterChain的过滤器,这个过滤器负责你的应用中所有的安全(保护应用程序 URL、验证提交的用户名和密码、重定向到表单中的日志等)。

  • 使用用户名user和在控制台打印出的随机生成的密码来创建一个UserDetailsService接口的实现bean

  • 注册一个名字为springSecurityFilterChain的过滤器,用来处理Sevlet容器中的所有请求

Spring Boot 的配置不多,但是做的事情很多。功能摘要如下:

Servlet Security:全局

介绍基于Servlet的应用中的Spring Security高级架构,是基于Authenticationopen in new window, Authorizationopen in new window, Protection Against Exploitsopen in new window的参考部分构建的高级架构

过滤器回顾

DelegatingFilterProxy

FilterChainProxy

SecurityFilterChain

FilterChainProxy会使用SecurityFilterChain来决定哪些Spring Security过滤器需要执行

简单来说SecurityFilterChain就是包含了一系列不同Spring Security过滤器

可能会有多个SecurityFilterChain,根据当前请求的URL来进行匹配,匹配到就将此SecurityFilterChain交给FilterChainProxy放入过滤器链中进行执行,从而会忽略掉其他的SecurityFilterChain

规则:优先第一个匹配到的过滤器链,具体代码见下图:

过滤链匹配
过滤链匹配

调试代码可以发现:当前有三个安全过滤器链,均是DefaultSecurityFilterChain的实例

前两个过滤器链分别针对oauth2授权服务和资源服务(项目集成了Spring-Security-oauth2),第三个则为Spring Security原本的过滤器链服务

过滤链截图
过滤链截图

对这三个安全过滤器链做一个简单的描述:

  • 授权服务配置生成

匹配规则:匹配请求/oauth/token,/oauth/token_key,/oauth/check_token

过滤器:

过滤器
过滤器
  • 资源服务器配置生成

匹配规则:NotOAuthRequestMatcher

过滤器:

过滤器
过滤器
  • WebSecurityConfigurer生成

匹配规则:所有请求

过滤器:

过滤器
过滤器

安全过滤器链集合的初始化过程

安全过滤器链集合是在项目启动的时候在配置类WebSecurityConfiguration的springSecurityFilterChain()方法中进行初始化的,上文有说到的自动装配会自动创建一个名为springSecurityFilterChain的过滤器就是由这个方法创建。 该方法内调用WebSecurity实例的build()方法进行过滤的构建。

WebSecurity实例中存在一个securityFilterChainBuilders属性,该属性用来存储过滤器链集合。

安全过滤链集合的初始化过程:

  1. WebSecurity实例执行build()方法过程中,调用内部方法doBuild()

  2. doBuild()内部调用this.init(),此内部会在WebSecurity的securityFilterChainBuilders集合中生成三个过滤器链的builder类(HttpSecurity),该对象有两个关键的属性filters和configurers。filters中有一个默认过滤器WebAsyncManagerIntegrationFilter,configurers有多个安全配置类

这里大概的逻辑就是获取到SecurityConfigurer集合,然后遍历配置类调用init方法。从调试结果可以看到有三个配置类:

  • org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerSecurityConfiguration

  • org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfiguration

  • com.iris.auth.config.SecurityConfiguration - 项目中对WebSecurityConfigurer接口对实现(实际上是继承适配器WebSecurityConfigurerAdapter)

SecurityConfigurers
SecurityConfigurers
// WebSecurity
private void init() throws Exception {
	Collection<SecurityConfigurer<O, B>> configurers = getConfigurers();

	for (SecurityConfigurer<O, B> configurer : configurers) {
		configurer.init((B) this);
	}

	for (SecurityConfigurer<O, B> configurer : configurersAddedInInitializing) {
		configurer.init((B) this);
	}
}
  1. this.init()执行完之后会继续调用performBuild(),在此内部会完成所有的过滤器链集合的初始化工作,大致逻辑如下:
  • 如果有需要忽略的请求,则设置一个默认的过滤器链DefaultSecurityFilterChain

  • 根据第2点中生成的securityFilterChainBuilders遍历调用build方法生成对应的过滤器链,实际上会遍历HttpSecurity的configurers内容调用对应configure方法添加过滤器,从整体上来说是一个递归调用的过程。

protected Filter performBuild() throws Exception {...
	int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
	List<SecurityFilterChain> securityFilterChains = new ArrayList<>(
			chainSize);
	for (RequestMatcher ignoredRequest : ignoredRequests) {
		securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
	}
	for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
		securityFilterChains.add(securityFilterChainBuilder.build());
	}
	FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
	if (httpFirewall != null) {
		filterChainProxy.setFirewall(httpFirewall);
	}
	filterChainProxy.afterPropertiesSet();

	Filter result = filterChainProxy;...
	postBuildAction.run();
	return result;
}

这三个安全配置类也是在调用相关的BeanPostProcess对WebSecurityConfiguration初始化的过程中,初始化setFilterChainProxySecurityConfigurer方法的时候进行插入的

提示

AuthorizationServerSecurityConfiguration 和 ResourceServerConfiguration分别是Oatuh2.0认证协议中的"授权服务器安全配置"和"资源服务器安全配置"

简单来说安全过滤器链的初始化过程和安全配置类有关系,整个过程中SecurityBuilder的实现类们起着至关重要的作用

总结:

  • 安全过滤器链的初始化的整个入口在WebSecurityConfiguration中,通过springSecurityFilterChain()将获取到的安全配置对象WebSecurityConfiguration进行构建(该类中会初始化系统中配置的其他安全配置对象)。

  • WebSecurityConfiguration构建的过程中会对其所包含的安全过滤器对象进行构建,所包含的安全过滤器对象可能还可能包含其他的子安全配置对象,不断递归完成所有构建过程

  • 对于每一个安全配置对象初始化子安全配置对象和过滤器的过程都在其对应的init方法中,一般是在其获取SecurityBuilder的过程中。对于每一个安全配置的build方法调用,大致就是重复去调用子安全配置对象的init方法。

下面是AuthorizationServer配置类的相关代码

安全配置对象
安全配置对象

configure(http)方法会调用我们实现AuthorizationServerConfigurer的对应方法

安全过滤器(Security Filters)

安全过滤器是由SecurityFilterChainAPI插入FilterChainProxy。过滤器的顺序很重要!通常不需要知道 Spring Security筛选器的顺序。然而,有时知道排序是有好处的。

以下是Spring Security排序的完整列表:

处理安全异常

ExceptionTranslationFilter过滤器允许将AccessDeniedExceptionAuthenticationException转换为HTTP响应

ExceptionTranslationFilter作为Security Filters的一部分插入FilterChainProxy

认证(Authentication)

Spring Security为身份验证提供了全面支持。本节讨论:

架构组件

本节介绍Spring Security在Servlet身份验证中使用的主要体系结构组件。如果您需要解释这些部分如何结合的具体流程,请查看认证机制的特定章节

  • SecurityContextHolder - Spring Security用来存储已认证用户open in new window的详细信息的地方

  • SecurityContext - 从SecurityContextHolder中获取,包含来当前已认证用户的Authentication(认证信息)

  • Authentication - 认证信息,可以是AuthenticationManager的输入,以提供用户为身份验证提供的凭据,也可以提供来自SecurityContext的当前用户

  • GrantedAuthority - Authentication授予主体的权力(即角色、范围等)

  • AuthenticationManager - 定义Spring Security过滤器如何执行身份验证open in new window的API。

  • ProviderManager - AuthenticationManager的最常见实现

  • AuthenticationProvider - ProviderManager用于执行特定类型的身份验证

  • Request Credentials with AuthenticationEntryPoint - 用于从客户端请求凭据(即重定向到登录页、发送 WWW 身份验证响应等)

  • AbstractAuthenticationProcessingFilter - 用于身份验证的基本筛选器。这还提供了高级身份验证流的好主意,以及部分如何协同工作

认证机制

  • Username and Password - how to authenticate with a username/password

  • OAuth 2.0 Login - OAuth 2.0 Log In with OpenID Connect and non-standard OAuth 2.0 Login (i.e. GitHub)

  • SAML 2.0 Login - SAML 2.0 Log In

  • Central Authentication Server (CAS) - Central Authentication Server (CAS) Support

  • Remember Me - How to remember a user past session expiration

  • JAAS Authentication - Authenticate with JAAS

  • OpenID - OpenID Authentication (not to be confused with OpenID Connect)

  • Pre-Authentication Scenarios - Authenticate with an external mechanism such as SiteMinder or Java EE security but still use Spring Security for authorization and protection against common exploits.

  • X509 Authentication - X509 Authentication