Spring Security
一、POM依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.2.0 RELEASE<version>
</dependency>
二、 默认配置
添加依赖后,即可实现Spring Security的默认配置。
spring-boot-autoconfigurer项目下的WebSecurityEnablerConfiguration 自动加载Spring Security 默认配置[WebSecurityConfigurerAdapter]
Spring Security 默认配置主要如下:
- URL拦截(未登录,重定向登录页面)
- 登录页面 [GET]/login
- 登录接口 [POST]/login [from-data]username=xxx&password=xxx&_csrf=xxx
- 登出页面 [GET]/logout
- 登出接口 [POST]/logout
- 默认账号 username=user&password=xxx[在项目启动时会输出初始密码 Using generated security password:xxx]
三、过滤器链
如果你是第一次使用Spring Security,一定会觉得很cool!Spring Security是如何做到的。
Spring Security主要基于过滤器(责任链模式)和AOP实现。
过滤器的结构大致是这么个意思
那么FilterChainProxy是如何构建出来的?
Spring Security提供了两个接口
-
SecurityBuilder<O> 泛型O代表构造器构建的对象类型
1.1 build() 构建并返回O对象 -
SecurityConfigurer<O,B extends SecurityBuilder<O>> 泛型B代表可配置的构造器类型,泛型O代表构造器构建的对象类型
2.1 init(B builder) 初始化SecurityBuilder
2.2 configure(B builder) 配置SecurityBuilder
Spring Security基于构造器模式,通过SecurityBuilder构造器构建对象,而SecurityConfigurer则负责对构造器进行初始化和配置。
FilterChainProxy通过WebSecurity构造器构建。
默认的WebSecurity在WebSecurityConfiguration.setFilterChainProxySecurityConfigurer()完成初始化,
并从Spring容器中获取SecurityConfigurers<Filter, WebSecurity>列表实现对构造器的初始化和配置。
package org.springframework.security.config.annotation.web.configuration;
@Configuration(proxyBeanMethods = false)
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
private WebSecurity webSecurity;
private List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers;
...
// 通过WebSecurity完成FilterChainProxy构建并注册到Spring容器
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
...
return webSecurity.build();
}
...
// 1 从spring容器中获取SecurityConfigurers<Filter, WebSecurity>配置列表
// 2 创建WebSecurity
// 3 将配置列表添加到WebSecurity
@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(
ObjectPostProcessor<Object> objectPostProcessor,
@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
throws Exception {
webSecurity = objectPostProcessor
.postProcess(new WebSecurity(objectPostProcessor));
...
for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
webSecurity.apply(webSecurityConfigurer);
}
...
}
...
}
SecurityFilterChain通过HttpSecurity构造器构建。
默认的HttpSecurity在WebSecurityConfigurerAdapter.init()完成初始化,该方法是WebSecurity在构建FilterChainProxy的过程中触发,并最终完成SecurityFilterChain构建添加到FilterChainProxy中。
package org.springframework.security.config.annotation.web.configuration;
@Order(100)
public abstract class WebSecurityConfigurerAdapter implements
WebSecurityConfigurer<WebSecurity> {
...
private HttpSecurity http;
private boolean disableDefaults;
...
// 初始化WebSecurity,在WebSecurity构建FilterChainProxy的过程中触发
public void init(final WebSecurity web) throws Exception {
final HttpSecurity http = getHttp();
web.addSecurityFilterChainBuilder(http)...;
}
...
// 配置WebSecurity
public void configure(WebSecurity web) {
}
...
// 创建并返回HttpSecurity
@SuppressWarnings({ "rawtypes", "unchecked" })
protected final HttpSecurity getHttp() throws Exception {
if (http != null) {
return http;
}
...
http = new HttpSecurity(objectPostProcessor, authenticationBuilder,
sharedObjects);
if (!disableDefaults) {
http
.csrf().and()
.addFilter(new WebAsyncManagerIntegrationFilter())
.exceptionHandling().and()
.headers().and()
.sessionManagement().and()
.securityContext().and()
.requestCache().and()
.anonymous().and()
.servletApi().and()
.apply(new DefaultLoginPageConfigurer<>()).and()
.logout();
ClassLoader classLoader = this.context.getClassLoader();
List<AbstractHttpConfigurer> defaultHttpConfigurers =
SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, classLoader);
for (AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
http.apply(configurer);
}
}
configure(http);
return http;
}
...
// 配置HttpSecurity
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().and()
.httpBasic();
}
...
}
下面则列出了一些"苦力"过滤器(默认过滤器列表)
当然,以下过滤器通常有对应的securityConfigurer完成构建。
构建逻辑在HttpSecurity的构建过程中,触发在其对应的SecurityConfigurer.configure(H http)中创建过滤器实例并添加到HttpSecurity中,最终添加到FilterChainProxy实例中。
1. WebAsyncManagerIntegrationFilter 支持集成Spring的异步调用
2. SecurityContextPersistenceFilter 从Session中获取SecurityContext,没有则新建,最终放入SecurityContextHolder中。
3. HeaderWriterFilter 往响应对象response中写入Header属性(Like X-Frame-Options, X-XSS-Protection and X- Content-Type-Options)
4. CsrfFilter csrf校验
5. LogoutFilter 默认拦截[POST]/logout 处理登出逻辑
6. UsernamePasswordAuthenticationFilter 默认拦截[POST]/login 处理登录认证逻辑
6.1 第一步 封装Authentication(从request中获取认证信息封装为UsernamePasswordAuthenticationToken)
6.2 第二步 获取AuthenticationManager实例[ProviderManager]
6.3 第三步 ProviderManager基于委托者模式通过AuthenticationProvider列表完成认证
6.4 第四步 认证通过后,将Authentication放入SecurityContextHolder的SecurityContext中。
7. DefaultLoginPageGeneratingFilter 默认拦截[GET]/login 生成登录页面
8. DefaultLogoutPageGeneratingFilter 默认拦截[POST]/login 生成登出页面
9. BasicAuthenticationFilter 认证Basic [Authorization: Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==]
10. RequestCacheAwareFilter 用于用户登录成功后,重新恢复因为登录被打断的请求
11. SecurityContextHolderAwareRequestFilter 包装request实现servlet api的一些接口方法isUserInRole、getRemoteUser
12. AnonymousAuthenticationFilter 匿名用户认证、信息填充
13. SessionManagementFilter Session管理
14. ExceptionTranslationFilter 异常处理
15. FilterSecurityInterceptor 权限校验、未登录拦截、无权限拦截
...
四、自定义配置
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。