前面几篇文章介绍了 Spring Security 中的各种功能组件,本文将结合 【Spring Security 系列】(一)入门篇 中的实际案例来介绍这些功能组件的默认实现,以及它们是如何通过配置作用到整个流程的。
通过了解组件的配置,可以让我们知道如何自定义整个流程中的各个环节。
UserDetailsService(用户信息查询):InMemoryUserDetailsManager:存储在内存的用户数据,默认内置一个帐号user,可以通过 spring.security.user 配置设置默认帐号密码。
UserDetails(用户信息):User
GrantedAuthority(权限信息):SimpleGrantedAuthority
PasswordEncoder(密码加密与验证):DelegatingPasswordEncoder
登录接口:UsernamePasswordAuthenticationFilter:POST /login
AuthenticationSuccessHandler(认证成功处理器):SavedRequestAwareAuthenticationSuccessHandler:默认重定向到首页 /,如果是因为访问其他路径异常导致重定向到登录页的,登录成功后会重定向到原来的路径。
AuthenticationFailureHandler(认证失败处理器):SimpleUrlAuthenticationFailureHandler:重定向到 /login?error登出接口:LogoutFilter:POST /logout
SimpleUrlLogoutSuccessHandler:重定向到 /login?logout异常处理:ExceptionTranslationFilter
AccessDeniedHandlerImpl:返回403LoginUrlAuthenticationEntryPoint:重定向到 /login鉴权拦截器:FilterSecurityInterceptor
CSRF安全:CsrfFilter
登录页:DefaultLoginPageGeneratingFilter:GET /login
登出页:DefaultLogoutPageGeneratingFilter:GET /logout
Spring Security 的核心配置类就是 WebSecurityConfigurerAdapter,但是我们在案例中并没有用到此类。这要归功于 SpringBoot 的自动配置。实际上是 SpringBootWebSecurityConfiguration 创建了 WebSecurityConfigurerAdapter 的 Bean,而此配置类则是通过 SecurityAutoConfiguration 使用 @Import 导入容器的。而SecurityAutoConfiguration 则是通过 SpringBoot 自动配置引入容器的。整体的关系表现为:
SpringBoot SPI -> SecurityAutoConfiguration -> SpringBootWebSecurityConfiguration -> WebSecurityConfigurerAdapter
WebSecurityConfigurerAdapter 中使用到了一个很重要的类 HttpSecurity,这个类是过滤器链 DefaultSecurityFilterChain 的构建类。DefaultSecurityFilterChain 其中包含了一系列的 Filtrer,Filter 才是核心。(比如上面的 UsernamePasswordAuthenticationFilter、LogoutFilter…)
WebSecurityConfigurerAdapter 中其实内置了默认的配置,这就使得我们的案例在不做任何配置的时候,还能正常运转(虽然只是demo级别)。默认配置体现在它的 getHttp()、configure(HttpSecurity http)方法中,比如 http.formLogin() 支持表单登录,也就是 UsernamePasswordAuthenticationFilter;比如 http.logout() 支持登出,也就是 LogoutFilter 等等。
自定义配置的方式也就是继承 WebSecurityConfigurerAdapter,示例:
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin().and()
.httpBasic();
}
}
end