spring security解析
Spring Security 中文文档 :: Spring Security Reference
1. 密码存储
最早是明文存储,但是攻击者获得数据库的数据后就能得到用户密码。
于是将密码单向hash后存储,然后攻击者利用彩虹表(算法高级(23)-彩虹表(Rainbow Table)_彩虹表下载-CSDN博客)可以快速的根据hash值获取密码。
于是人们将密码加盐后hash,这种方式增加了存储密码的复杂度,使得预先根据简单字符串生成的彩虹表不会那么容易的匹配到存储的复杂密码hash值。
但是现代硬件每秒几十亿次hash计算,可以轻松的暴力破解(依次尝试各种字节组合,并匹配存储的hash值)。
2. 配置类加载
spring-boot-autoconfigure-3.4.4.jar!\META-INF\spring\org.springframework.boot.autoconfigure.AutoConfiguration.imports
springboot会扫描并加载该文件中的配置类
org.springframework.boot.autoconfigure.security.servlet.SpringBootWebSecurityConfiguration.SecurityFilterChainConfiguration#defaultSecurityFilterChain:springboot默认在该方法中注册SecurityFilterChain
filter注册到servlet容器的过程:
首先,DelegatingFilterProxyRegistrationBean(实现了ServletContextInitializer)在SecurityFilterAutoConfiguration(在imports文件中)中被注册为一个bean,然后,其在context容器初始化时注册了DelegatingFilterProxy过滤器。SecurityFilterAutoConfiguration中使用springSecurityFilterChain作为受委托的filter。springSecurityFilterChain通过WebSecurityConfiguration注册为bean,WebSecurityConfiguration是由SpringBootWebSecurityConfiguration的内部类WebSecurityEnablerConfiguration注册的,SpringBootWebSecurityConfiguration是在SecurityAutoConfiguration(在imports中)中导入的。
springSecurityFilterChain是一个FilterChainProxy类型的bean
DefaultSecurityFilterChain在SecurityFilterChainConfiguration中被注册
3. 过滤器
DelegatingFilterProxy:使用过滤器bean来实现过滤,是sevlet容器标准与spring bean之间的桥梁。sevlet容器可以通过自己的标准注册filter,但是无法检测到spring bean,于是先注册DelegatingFilterProxy作为标准过滤器,然后DelegatingFilterProxy将工作委托给spring的过滤器bean。DelegatingFilterProxy的另一个好处是延迟查找filter bean,servlet容器需要在启动前完成filter的注册,但是使用DelegatingFilterProxy的话可以在servlet容器启动后再完成filter bean的加载。作为一个Filter的代理,将工作委托给filter bean。
FilterChainProxy:一个filter bean,可以链式调用多个filter,包含在DelegatingFilterProxy,被委托来执行过滤工作。包含多个SecurityFilterChain,每个SecurityFilterChain含有0个或多个filter,根据请求确定使用哪个SecurityFilterChain。
SecurityFilterChain:包含多个filter。
多个SecurityFilterChain的图示:
ExceptionTranslationFilter:将 AccessDeniedException 和 AuthenticationException 翻译成 HTTP 响应。
异常处理图示:
1 首先,
ExceptionTranslationFilter
调用FilterChain.doFilter(request, response)
来调用应用程序的其他部分。2 如果用户没有被认证,或者是一个
AuthenticationException
,那么就 开始认证。
SecurityContextHolder 被清理掉。
HttpServletRequest
被保存起来,这样一旦认证成功,它就可以用来重放原始请求。
AuthenticationEntryPoint
用于请求客户的凭证。例如,它可以重定向到一个登录页面或发送一个WWW-Authenticate
头。3 否则,如果是
AccessDeniedException
,那么就是 Access Denied。AccessDeniedHandler
被调用来处理拒绝访问(access denied)。
RequestCacheAwareFilter:使用 RequestCache 来保存 HttpServletRequest
保存认证前的请求,以在认证后继续访问:
@Bean DefaultSecurityFilterChain springSecurity(HttpSecurity http) throws Exception { HttpSessionRequestCache requestCache = new HttpSessionRequestCache(); requestCache.setMatchingRequestParameterName("continue"); http // ... .requestCache((cache) -> cache .requestCache(requestCache) ); return http.build(); }
不保存请求:
@Bean
SecurityFilterChain springSecurity(HttpSecurity http) throws Exception {
RequestCache nullRequestCache = new NullRequestCache();
http
// ...
.requestCache((cache) -> cache
.requestCache(nullRequestCache)
);
return http.build();
}
注意:当你把你的 filter 声明为 Spring Bean 时要小心,可以用 @Component
注解它,也可以在配置中把它声明为 Bean,因为 Spring Boot 会自动 在嵌入式容器中注册它。这可能会导致 filter 被调用两次,一次由容器调用,一次由 Spring Security 调用,而且顺序不同。另外自定义的filter可以从 OncePerRequestFilter 中继承,而不是实现 Filter
,这是一个基类,用于每个请求只调用一次的 filter,并提供一个带有 HttpServletRequest
和 HttpServletResponse
参数的 doFilterInternal
方法。
自定义过滤器:
@Bean
SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ...
.addFilterBefore(new TenantFilter(), AuthorizationFilter.class);
return http.build();
}
4. 日志
logging.level.org.springframework.security=TRACE