SpringSecurity源码学习(一)

前言

本文讨论基于java配置的SpringSecurity源码学习。

从Servlet3.0谈起

Servlet3.0以后推荐使用基于java的方式来配置servlet容器,以替代传统的web.xml.

ServletContainerInitializer

容器会在类路径下找实现了javax.servlet.ServletContainerInitializer接口的类,如果能发现的话就使用它来配置servlet容器。替代传统的web.xml的功能。

SpringServletContainerInitializer

Spring提供了Servlet标准接口的实现类:SpringServletContainerInitializer,这个类牛逼之处在于:又会在”类路径”下查找实现了WebApplicationInitizer接口的所有类,并将真正配置的任务委托给它来实现。具体源码如下,注意看它的参数含义:

    /*
     * @param webAppInitializerClasses all implementations of
     * {@link WebApplicationInitializer} found on the application classpath
     * @param servletContext the servlet context to be initialized
     */
    @Override
    public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) {
                .....
    }

AbstractSecurityWebApplicationInitializer

这个类是SpringSecurity提供的WebApplicationInitializer的子类。主要做的事情就是:创建DelegatingFilterProxy(“过滤器链代理的委派”),本质上它就是一个过滤器,默认name=springSecurityFilterChain,urlPatterns=/*。意味着,所有的请求都要经过SpringSecurity的处理(包括静态资源哦)

    public final void onStartup(ServletContext servletContext) throws ServletException {
        beforeSpringSecurityFilterChain(servletContext);
        if (this.configurationClasses != null) {
            AnnotationConfigWebApplicationContext rootAppContext = new AnnotationConfigWebApplicationContext();
            rootAppContext.register(this.configurationClasses);
            servletContext.addListener(new ContextLoaderListener(rootAppContext));
        }
        if (enableHttpSessionEventPublisher()) {
            servletContext.addListener(
                    "org.springframework.security.web.session.HttpSessionEventPublisher");
        }
        servletContext.setSessionTrackingModes(getSessionTrackingModes());
        //这里就是具体的创建并向Servlet容器中注册
        insertSpringSecurityFilterChain(servletContext);
        afterSpringSecurityFilterChain(servletContext);
    }

DelegatingFilterProxy

过滤器链代理的委派。前面提到,它本质上是一个Filter,并且它拦截了所有的请求。它其实是SpringSecurity权限管理的入口。它既然是Filter,那么我们就看下它的doFilter()是怎么处理请求的:

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        // Lazily initialize the delegate if necessary.
        Filter delegateToUse = this.delegate;
        if (delegateToUse == null) {
            synchronized (this.delegateMonitor) {
                if (this.delegate == null) {
                    WebApplicationContext wac = findWebApplicationContext();
                    if (wac == null) {
                        throw new IllegalStateException("No WebApplicationContext found: " +
                                "no ContextLoaderListener or DispatcherServlet registered?");
                    }
                    //去spring的web容器中找name=springSecurityFilterChain的bean
                    this.delegate = initDelegate(wac);
                }
                delegateToUse = this.delegate;
            }
        }

        // Let the delegate perform the actual doFilter operation.
        invokeDelegate(delegateToUse, request, response, filterChain);
    }

所以从这里可以看出,它确实是一个“代理”,它接受到请求之后,将请求委派给spring web容器中name=springSecurityFilterChain的bean。

从@EnableWebSecurity谈起

基于java配置的SpringSecurity,一般都有这么一个配置类:

@EnableWebSecurity
@ComponentScan("fn.wd.security")
public class SpringSecurityConfiger extends WebSecurityConfigurerAdapter {
    ...
}

@EnableWebSecurity其实是一个复合注解

@Import({ WebSecurityConfiguration.class, ObjectPostProcessorConfiguration.class,
        SpringWebMvcImportSelector.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {}

啰嗦一下,@Import就类似于xml配置文件中的,后者用于导入其他配置文件(xml),前者用于导入其他配置类(.class)。
所以从这可以看出,这个注解其实导入了三个配置类。

ObjectPostProcessorConfiguration

被导入的配置类之一,很简单,就创建了一个AutowireBeanFactoryObjectPostProcessor。

    @Bean
    public ObjectPostProcessor<Object> objectPostProcessor(
            AutowireCapableBeanFactory beanFactory) {
        return new AutowireBeanFactoryObjectPostProcessor(beanFactory);
    }

AutowireBeanFactoryObjectPostProcessor

它是ObjectPostProcessor的一个实现类,作用是,当手动创建一个对象后(一般手动指的是new xxx()),使用这个后置处理器,为手动创建的类完成依赖注入的功能。

举个例子:

    Class A implements BeanFactoryAware{
        private BeanFactory beanFactory;

        public void setBeanFactory(BeanFactory beanFactory){
            this.beanFactory=beanFactory;
        }

        ...
    }

    Class App{
        public static void main(String[] args){
            //a是手动创建的,虽然是实现了BeanFactoryAware,但是Spring才不会搭理你
            A a=new A();

            //假设这里获得了那个后置处理器
            autowireBeanFactoryObjectPostProcessor.process(a);

            //这样a就能享受spring依赖注入的待遇了

        }
    }

这个类还是比较重要的。后面会经常用到。关于这个类,知道它是做什么的就好了。

SpringWebMvcImportSelector

被导入的配置类之一,也比较简单,判断当前是不是SpringMVC环境(看看DispactherServlet在不在类路径下),如果是的话,导入SpringMVC的配置类:WebMvcSecurityConfiguration。

WebSecurityConfiguration

导入的配置类之一。这个算是整个SpringSecurity的配置类了。看它做了些什么?

1). 创建AutowiredWebSecurityConfigurersIgnoreParents

创建了一个AutowiredWebSecurityConfigurersIgnoreParents对象,并放入容器中:

@Bean
public AutowiredWebSecurityConfigurersIgnoreParents autowiredWebSecurityConfigurersIgnoreParents(
            ConfigurableListableBeanFactory beanFactory) {
        return new AutowiredWebSecurityConfigurersIgnoreParents(beanFactory);
    }

这个类是干什么用的呢?
答:获取Spring Web容器中的所有类型为WebSecurityConfigurer的bean。源码如下:

public List<SecurityConfigurer<Filter, WebSecurity>> getWebSecurityConfigurers() {
        List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = new ArrayList<SecurityConfigurer<Filter, WebSecurity>>();
        Map<String, WebSecurityConfigurer> beansOfType = beanFactory
                .getBeansOfType(WebSecurityConfigurer.class);
        for (Entry<String, WebSecurityConfigurer> entry : beansOfType.entrySet()) {
            webSecurityConfigurers.add(entry.getValue());
        }
        return webSecurityConfigurers;
    }

2). 设置FilterChainProxy的构建器

获取spring web容器中“过滤器链代理”的所有“配置器”,并将其设置到“过滤器链代理”的“构建器”中。

@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(
            ObjectPostProcessor<Object> objectPostProcessor,
@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
            throws Exception {
            ...
}

注意:这里有一个spel的高阶用法:

@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}")

它的意思是,获取容器中的name=autowiredWebSecurityConfigurersIgnoreParents的bean对象,将其getWebSecurityConfigurers()的返回值注入到webSecurityConfigurers属性中。

3). 创建过滤器链代理

前面谈到,“过滤器链代理的委派”过滤器将接受到的请求转发给“过滤器链代理”来处理,那这个过滤器链代理是在哪里创建的呢?诺,就在这,创建出来的bean的name正是:springSecurityFilterChain

    @Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
    public Filter springSecurityFilterChain() throws Exception {
        boolean hasConfigurers = webSecurityConfigurers != null
                && !webSecurityConfigurers.isEmpty();
        if (!hasConfigurers) {
            WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
                    .postProcess(new WebSecurityConfigurerAdapter() {
                    });
            webSecurity.apply(adapter);
        }
        return webSecurity.build();
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值