security详解

本文详细介绍了Spring Security的自动注入、请求处理流程及重要元素关系,包括SecurityBuilder、AuthenticationManager、AuthenticationProvider等的关系图,并探讨了配置自定义provider、UserDetailsService等的方法。
摘要由CSDN通过智能技术生成

spring security + Oauth2.0


一.spring security

问:

  1. spring security是如何注入spring容器?
  2. filter是如何加入tomcat?
  3. spring security是如何起作用?

1.自动注入

springboot在启动时会扫描所有jar包下的spring.factories,并且利用工具类转换成Map<String,List>对象,其中org.springframework.boot.autoconfigure.EnableAutoConfiguration就是自动注入的关键。

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityRequestMatcherProviderAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration

首先我们来看看这个类SecurityAutoConfiguration.java

@Configuration
//条件,如果有这个类则注入
@ConditionalOnClass({
   DefaultAuthenticationEventPublisher.class})
//自动注入参数
@EnableConfigurationProperties({
   SecurityProperties.class})
//导入三个配置类
@Import({
   SpringBootWebSecurityConfiguration.class, WebSecurityEnablerConfiguration.class, SecurityDataConfiguration.class})
public class SecurityAutoConfiguration {
   
    public SecurityAutoConfiguration() {
   
    }

    @Bean
    //容器中不存在这个类
    @ConditionalOnMissingBean({
   AuthenticationEventPublisher.class})
    public DefaultAuthenticationEventPublisher authenticationEventPublisher(ApplicationEventPublisher publisher) {
   
        return new DefaultAuthenticationEventPublisher(publisher);
    }
}

然后我们再看看三个配置类干了些什么

/**
 *SpringBootWebSecurityConfiguration
 */
@Configuration
//存在这个class
@ConditionalOnClass({
   WebSecurityConfigurerAdapter.class})
//容器中没有这个类及其子类
@ConditionalOnMissingBean({
   WebSecurityConfigurerAdapter.class})
//条件是web环境
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
public class SpringBootWebSecurityConfiguration {
   
    public SpringBootWebSecurityConfiguration() {
   
    }

    @Configuration
    @Order(2147483642)
    //如果以上条件成立生成默认WebSecurityConfigurerAdapter,这也是我们不做任何配置security能生效的原因
    static class DefaultConfigurerAdapter extends WebSecurityConfigurerAdapter {
   
        DefaultConfigurerAdapter() {
   
        }
    }
}



----------------------------------------------------------------------------------------
/**
 *WebSecurityEnablerConfiguration
 */
@Configuration
@ConditionalOnBean({
   WebSecurityConfigurerAdapter.class})
@ConditionalOnMissingBean(
    name = {
   "springSecurityFilterChain"}
)
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
//1.引入三个类(WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class)
//2.@EnableGlobalAuthentication注解(引入AuthenticationConfiguration.class)
@EnableWebSecurity
public class WebSecurityEnablerConfiguration {
   
    public WebSecurityEnablerConfiguration() {
   
    }
}

引入的类的作用:.==WebSecurityConfiguration.class==
    1.注入springSecurityFilterChain,并把WebSecurityConfigurerAdapter添加到webSecurity
    2.注入SecurityExpressionHandler
    3.注入DelegatingApplicationListener

二.==SpringWebMvcImportSelector.class==
    如果有dispatcherservlet.class返回WebMvcSecurityConfiguration全类名

三.==OAuth2ImportSelector.class==
    如果存在OAuth2ClientConfiguration.class返回OAuth2ClientConfiguration全类名

四.注解@EnableGlobalAuthentication
	导入AuthenticationConfiguration.class
		1.导入ObjectPostProcessorConfiguration.class
            注入ObjectPostProcessor<Object>
		2.注入AuthenticationManagerBuilder
		3.注入GlobalAuthenticationConfigurerAdapter
---------------------------------------------------------------------------------------
/**
 *SecurityDataConfiguration
 */
@Configuration
@ConditionalOnClass({
   SecurityEvaluationContextExtension.class})
public class SecurityDataConfiguration {
   
    public SecurityDataConfiguration() {
   
    }

    @Bean
    @ConditionalOnMissingBean
    //安全表达式扩展
    public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
   
        return new SecurityEvaluationContextExtension();
    }
}

接下来看看SecurityRequestMatcherProviderAutoConfiguration

@Configuration
@ConditionalOnClass({
   RequestMatcher.class})
@ConditionalOnWebApplication(
    type = Type.SERVLET
)
public class SecurityRequestMatcherProviderAutoConfiguration {
   
    public SecurityRequestMatcherProviderAutoConfiguration() {
   
    }

    @Configuration
    @ConditionalOnClass({
   DispatcherServlet.class})
    @ConditionalOnBean({
   HandlerMappingIntrospector.class})
    public static class MvcRequestMatcherConfiguration {
   
        public MvcRequestMatcherConfiguration() {
   
        }

        @Bean
        @ConditionalOnClass({
   DispatcherServlet.class})
        //注入MvcRequestMatcherProvider
        public RequestMatcherProvider requestMatcherProvider(HandlerMappingIntrospector introspector) {
   
            return new MvcRequestMatcherProvider(introspector);
        }
    }
}

下面到了SecurityFilterAutoConfiguration

@AutoConfigureAfter
public class SecurityFilterAutoConfiguration {
   
    private static final String DEFAULT_FILTER_NAME = "springSecurityFilterChain";

    @Bean
    @ConditionalOnBean(
        name = {
   "springSecurityFilterChain"}
    )
    //这个类实现了RegistrationBean,会在初始化时调用钩子函数onStartup(ServletContext servletContext),这个方法会最终调用父类AbstractFilterRegistrationBean的addRegistration(String description, ServletContext servletContext) 将DelegatingFilterProxy(filter的实现类)添加到ServletContext
    public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration(SecurityProperties securityProperties) {
   
        DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean("springSecurityFilterChain", new ServletRegistrationBean[0]);
        registration.setOrder(securityProperties.getFilter().getOrder());
        registration.setDispatcherTypes(this.getDispatcherTypes(securityProperties));
        return registration;
    }

    private EnumSet<DispatcherType> getDispatcherTypes(SecurityProperties securityProperties) {
   
        return securityProperties.getFilter().getDispatcherTypes() == null ? null : (EnumSet)securityProperties.getFilter().getDispatcherTypes().stream().map((type) -> {
   
            return DispatcherType.valueOf(type.name());
        }).collect(Collectors.collectingAndThen(Collectors.toSet(), EnumSet::copyOf));
    }
}

在这里插入图片描述

tomcat启动时,TomcatStarter会遍历ServletContextInitializer[] initializers;调用所有实现ServletContextInitializer的onStartup(),而此刻会将DelegatingFilterProxy加入到ServletContext的实现类ApplicationContext的StandardContext(TomcatEmbeddedContext(为StandardContext实现类))中


protected Dynamic addRegistration(String description, ServletContext servletContext) {
   
        Filter filter = this.getFilter();
        return servletContext.addFilter(this.getOrDeduceName(filter), filter);
}

在这里插入图片描述

此时,初始化已经完毕,springSecurityFilterChain已经加入到tomcat。

tomcat结构图

<Server>顶层类元素:一个配置文件中只能有一个<Server>元素,可包含多个Service。
    <Service>顶层类元素:本身不是容器,可包含一个Engine,多个Connector。
        <Connector/>连接器类元素:代表通信接口。
        <Engine>容器类元素:为特定的Service组件处理所有客户请求,可包含多个Host。engine为顶层Container
           <Host>容器类元素:为特定的虚拟主机处理所有客户请求,可包含多个Context。
              <Context>容器类元素:为特定的Web应用处理所有客户请求。代表一个应用,包含多个Wrapper(封装了servlet)
              </Context>
           </Host>
        </Engine>
     </Service>
</Server>

2.当请求到达tomcat

首先请求会到达Acceptor类,Acceptor 继承了 AbstractEndpoint.Acceptor ,间接实现了Runnable接口,tomcat在运行时将Acceptor运行在一个后台线程内,单独监听socket请求,

protected class Acceptor extends AbstractEndpoint.Acceptor {
   
    @Override
    public void run() {
   
        // Loop until we receive a shutdown command
        while (running) {
   
            //if we have reached max connections, wait
            countUpOrAwaitConnection();

            Socket socket = null;
            //阻塞住 监听新的socket请求
            socket = serverSocketFactory.acceptSocket(serverSocket);

            // Configure the socket
            if (running && !paused && setSocketOptions(socket)) {
   
                // Hand this socket off to an appropriate processor 首先使用processSocket()简单处理socket
                if (!processSocket(socket)) {
   
                    countDownConnection();
                    // Close socket right away
                    closeSocket(socket);
                }
            } else {
   
                countDownConnection();
                // Close socket right away
                closeSocket(socket);
            }

        }
    }
}

//接着进入processSocket(Socket socket)方法,processSocket方法主要工作为将socket请求信息进行封装,然后将一个实现了Runnable接口的并包含socket信息的SocketProcessor对象交给线程池,进行执行,然后Acceptor线程从该方法返回,重新监听端口上的socket请求。
protected boolean processSocket(Socket socket) {
   
    // Process the request from this socket
    SocketWrapper<Socket> wrapper = new SocketWrapper<Socket>(socket);
    wrapper.setKeepAliveLeft(getMaxKeepAliveRequests
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值