SpringSecurity源码解读

1.前言

官方解释如下

Spring Security is a powerful and highly customizable authentication and access-control framework. 
It is the de-facto standard for securing Spring-based applications. Spring Security is a framework that focuses on providing both authentication and authorization to Java applications.
Like all Spring projects, the real power of Spring Security is found in how easily it can be extended to meet custom requirements.

https://spring.io/projects/spring-security

 

SpringSecurity项目继承WebSecurityConfigurerAdapter完成拦截鉴权逻辑,如下

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/", "/home").permitAll()
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
                .logout()
                .permitAll();
    }
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
                .withUser("admin").password(new BCryptPasswordEncoder().encode("admin")).roles("USER");
    }
}

 

Spring鉴权认证思路就是利用J2EE的Filter,上面的WebSecurityConfigurerAdapter大量的configure操作,最终目的就是为了创建一个FilterChainProxy(bean's name: springSecurityFilterChain)实例。

 为了分析SpringSecurity框架原理,本文带大家追溯源码,分析springSecurityFilterChain的定义初始化过程。

 

1.启动入口

J2EE定义了javax.servlet.ServletContainerInitializer接口,就是为了替换以前普通的web项目的web.xml功能,使用者可以使用ServletContainerInitializer和SPI完成servlet/filter/listener定义,可以看官方文档定义

Spring Framework定义了SpringServletContainerInitializer类和WebApplicationInitializer接口,SpringBoot也定义了函数接口org.springframework.boot.web.servlet.ServletContextInitializer,两者功能类似,都是替换web.xml定义使用的,但是SpringBoot新定义类可以解决war包的冲突问题,场景如:

假如项目pay-web打包为pay-web.war,pay-web.war同时包含了SpringBoot和SpringFramework相关类,但pay-web.war只用到SpringFramework的特性,跑在Tomcat容器。

容器在加载SpringFramework的SpringServletContainerInitializer,会默认寻找类路径所有的WebApplicationInitializer实现类,这个SpringBoot的starter复用SpringFramework接口WebApplicationInitializer,实现了相关的逻辑,那么会出现问题。

所以SpringBoot单独定义了一个ServletContextInitializer类。详细可以看官方文档

 

SpringBoot使用的AnnotationConfigServletWebServerApplicationContext的容器,它父类ServletWebServerApplicationContext的onRefresh方法提供了构建webServer细节,即从Spring的BeanFactory获取所有的ServletContextInitializer类。

SpringSecurity使用SecurityFilterAutoConfiguration构建了DelegatingFilterProxyRegistrationBean实例。

 而我们的DelegatingFilterProxyRegistrationBean刚好就是一个ServletContextInitializer的实现类。

DelegatingFilterProxyRegistrationBean执行onStartup()方法逻辑,会注册Filter到ServletContext中,如下

上图所示,留意上面的$1,所以Filter的实现类是一个DelegatingFilterProxy匿名继承类

 

2.小结

  a).SpringBoot初始化SpringSecurity的@Configuration类,构建一个匿名类DelegatingFilterProxyRegistrationBean$1实例,这个匿名类继承DelegatingFilterProxy

  b).匿名类DelegatingFilterProxyRegistrationBean$1实例(继承DelegatingFilterProxy)包裹了springSecurityFilterChain实例。

  c).匿名类DelegatingFilterProxyRegistrationBean$1实例注册Filter映射url(默认为/*)到ServletContext中。

 

3.springSecurityFilterChain加载

SpringSecurity通过类WebSecurityConfiguration定义了一个bean名为springSecurityFilterChain的实例,如下。

 上图显示springSecurityFilterChain实质上是通过WebSecurity调用build方法完成构建的,下面是WebSecurity的performBuild详情

所以,我们的springSecurityFilterChain实例实质上是FilterChainProxy类型,FilterChainProxy有两类组成:

  a).ignoredRequests生成的DefaultSecurityFilterChain实例

  b).模板类SecurityBuilder(实质上就是HttpSecurity类)调用buid方法生成的实例。

上图所示,HttpSecurity就是上面内容"前言"例子的configure参数HttpSecurity,所以我们通过WebSecurityConfigurerAdapter调用configure方法配置HttpSecurity结果会在这里用上。

4.HttpSecurity构建

 未完待续……

posted on 2019-01-10 18:34  小东dylanli  阅读(676)  评论(0编辑  收藏  举报

导航