• SpringSecurity的@EnableWebSecurity注解


    SpringSecurity的@EnableWebSecurity注解

    @EnableWebSecurity

    @EnableWebSecurity是开启SpringSecurity的默认行为,它的上面有一个Import注解导入了WebSecurityConfiguration类,也就是说我们加上了@EnableWebSecurity这个注解,就是往IOC容器中注入了WebSecurityConfiguration这个类。

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ElementType.TYPE})
    @Documented
    @Import({WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class})
    @EnableGlobalAuthentication
    @Configuration
    public @interface EnableWebSecurity {
        boolean debug() default false;
    }
    
    

    它还有一个debug的功能,如果设置为true,则开启debug功能,每个经过那些过滤器都会被展示出来。

    image-20210808122218037

    WebSecurityConfiguration

    WebSecurityConfiguration用来配置初始化webSecurity的,在setFilterChainProxySecurityConfigurer方法中,它以配置SpringSecurity时继承自WebSecurityConfigurerAdapter的配置类来初始化SecurityConfigurer列表,来启用所需的安全策略

     @Autowired(
            required = false
        )
        public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor, @Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers) throws Exception {
            this.webSecurity = (WebSecurity)objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
            if (this.debugEnabled != null) {
                this.webSecurity.debug(this.debugEnabled);
            }
    
            webSecurityConfigurers.sort(WebSecurityConfiguration.AnnotationAwareOrderComparator.INSTANCE);
            Integer previousOrder = null;
            Object previousConfig = null;
    
            Iterator var5;
            SecurityConfigurer config;
            for(var5 = webSecurityConfigurers.iterator(); var5.hasNext(); previousConfig = config) {
                config = (SecurityConfigurer)var5.next();
                Integer order = WebSecurityConfiguration.AnnotationAwareOrderComparator.lookupOrder(config);
                if (previousOrder != null && previousOrder.equals(order)) {
                    throw new IllegalStateException("@Order on WebSecurityConfigurers must be unique. Order of " + order + " was already used on " + previousConfig + ", so it cannot be used on " + config + " too.");
                }
    
                previousOrder = order;
            }
    
            var5 = webSecurityConfigurers.iterator();
    
            while(var5.hasNext()) {
                config = (SecurityConfigurer)var5.next();
                //将配置的每一个SecurityConfigurer列表传递给 webSecurity
                this.webSecurity.apply(config);
            }
    
            this.webSecurityConfigurers = webSecurityConfigurers;
        }
    

    WebSecurityConfiguration这个类的创建流程也是经过spring容器初始化的那一整套。

    image-20210808131543640

    因为我们配置的SpringSecurityConfig这个类,继承了WebSecurityConfigurerAdapter,它又实现了SecurityConfigurer这个接口,所以在配置的时候,能拿到我们这个配置类里面的信息,具体如图:

    image-20210808133759715

    接着创建过滤器链

    //提供一个名叫springSecurityFilterChain的bean,返回一个Filter对象
    @Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
    	public Filter springSecurityFilterChain() throws Exception {
    		boolean hasConfigurers = webSecurityConfigurers != null
    				&& !webSecurityConfigurers.isEmpty();
    		if (!hasConfigurers) {
                 //如果没有配置过Spring Security,则会议WebSecurityConfigurerAdapter中的配置作为默认,上面能拿到我们的配置,因此就不走这段逻辑
    			WebSecurityConfigurerAdapter
    WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
    					.postProcess(new WebSecurityConfigurerAdapter() {
    					});
    			webSecurity.apply(adapter);
    		}
    		return webSecurity.build();
    	}
    

    以前在Spring的配置中,会有一个web.xml,在里面配置过滤器,但是现在SpringBoot已经自动配置了web.xml. DelegatingFilterProxy是Spring提供的一个标准Servlet Filter代理,并代理改bean提供的过滤器,也就是说,在这个配置中,最终起作用的过滤器是什么完全取决于springSecurityFilterChain。

    @Configuration(proxyBeanMethods = false)
    @ConditionalOnWebApplication(type = Type.SERVLET)
    @EnableConfigurationProperties(SecurityProperties.class)
    @ConditionalOnClass({ AbstractSecurityWebApplicationInitializer.class, SessionCreationPolicy.class })
    @AutoConfigureAfter(SecurityAutoConfiguration.class)
    public class SecurityFilterAutoConfiguration {
    
    	private static final String DEFAULT_FILTER_NAME = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME;
    
    	@Bean
    	@ConditionalOnBean(name = DEFAULT_FILTER_NAME)
    	public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration(
    			SecurityProperties securityProperties) {
    		DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean(
    				DEFAULT_FILTER_NAME);
    		registration.setOrder(securityProperties.getFilter().getOrder());
    		registration.setDispatcherTypes(getDispatcherTypes(securityProperties));
    		return registration;
    	}
    
    	private EnumSet<DispatcherType> getDispatcherTypes(SecurityProperties securityProperties) {
    		if (securityProperties.getFilter().getDispatcherTypes() == null) {
    			return null;
    		}
    		return securityProperties.getFilter().getDispatcherTypes().stream()
    				.map((type) -> DispatcherType.valueOf(type.name()))
    				.collect(Collectors.toCollection(() -> EnumSet.noneOf(DispatcherType.class)));
    	}
    
    }
    

    前面说的springSecurityFilterChain是由 webSecurity.build()这个创建的,最终调用的是doBuild方法,是由AbstractConfiguredSecurityBuilder提供的

    
    
    public final O build() throws Exception {
    		if (this.building.compareAndSet(false, true)) {
    			this.object = doBuild();
    			return this.object;
    		}
    		throw new AlreadyBuiltException("This object has already been built");
    	}
    

    AbstractConfiguredSecurityBuilder的doBuild调用的是WebSecurity的performBuild()方法

    @Override
    	protected final O doBuild() throws Exception {
    		synchronized (configurers) {
                //安装状态依次执行相应的方法
    			buildState = BuildState.INITIALIZING;
    
    			beforeInit();
                //初始化状态,通过调用WebSecurityConfigurerAdapter的init,将所有HttpSecurity添加到WebSecurity里
    			init();
    
    			buildState = BuildState.CONFIGURING;
    
    			beforeConfigure();
    			configure();
    
    			buildState = BuildState.BUILDING;
          //在BUILDING阶段调用WebSecurity的performBuild方法
    			O result = performBuild();
    
    			buildState = BuildState.BUILT;
    
    			return result;
    		}
    	}
    

    在init方法中,初始化状态,通过调用WebSecurityConfigurerAdapter的init,将所有HttpSecurity添加到WebSecurity里

    image-20210808135049557

    在performBuild方法中,SpringSecurity完成了所有过滤器的创建,最终返回一个过滤器链代理类filterChainProxy.

    @Override
    	protected Filter performBuild() throws Exception {
    		Assert.state(
    				!securityFilterChainBuilders.isEmpty(),
    				() -> "At least one SecurityBuilder<? extends SecurityFilterChain> needs to be specified. "
    						+ "Typically this done by adding a @Configuration that extends WebSecurityConfigurerAdapter. "
    						+ "More advanced users can invoke "
    						+ WebSecurity.class.getSimpleName()
    						+ ".addSecurityFilterChainBuilder directly");
    		int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
    		List<SecurityFilterChain> securityFilterChains = new ArrayList<>(
    				chainSize);
    		for (RequestMatcher ignoredRequest : ignoredRequests) {
    			securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
    		}
             //简单来说,就是每一个HttpSecurity生成一个过滤器链,HttpSecurity则来自我们配置的WebSecurityConfigure
    		for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
    			securityFilterChains.add(securityFilterChainBuilder.build());
    		}
    		FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
    		if (httpFirewall != null) {
    			filterChainProxy.setFirewall(httpFirewall);
    		}
    		filterChainProxy.afterPropertiesSet();
    
    		Filter result = filterChainProxy;
    		if (debugEnabled) {
    			logger.warn("
    
    "
    					+ "********************************************************************
    "
    					+ "**********        Security debugging is enabled.       *************
    "
    					+ "**********    This may include sensitive information.  *************
    "
    					+ "**********      Do not use in a production system!     *************
    "
    					+ "********************************************************************
    
    ");
    			result = new DebugFilter(filterChainProxy);
    		}
    		postBuildAction.run();
    		return result;
    	}
    

    image-20210808134236782

    filterChainProxy间接继承了FIlter,可以作为真正的过滤器使用,它会携带若干条过滤器链,并在承担过滤器职责时,将其派发到所有过滤器链的每一个过滤器上。

    @Override
    	public void doFilter(ServletRequest request, ServletResponse response,
    			FilterChain chain) throws IOException, ServletException {
    		boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;
    		if (clearContext) {
    			try {
    				request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
    				doFilterInternal(request, response, chain);
    			}
    			finally {
    				SecurityContextHolder.clearContext();
    				request.removeAttribute(FILTER_APPLIED);
    			}
    		}
    		else {
    			doFilterInternal(request, response, chain);
    		}
    	}
    

    doFilterInternal是真正执行虚拟过滤器链逻辑的方法

    private void doFilterInternal(ServletRequest request, ServletResponse response,
    			FilterChain chain) throws IOException, ServletException {
        //附上Spring Security提供的HTTP防火墙
    		FirewalledRequest fwRequest = firewall
    				.getFirewalledRequest((HttpServletRequest) request);
    		HttpServletResponse fwResponse = firewall
    				.getFirewalledResponse((HttpServletResponse) response);
         //按照配置的RequestMatcher,决定每一个请求会经过那些过滤器
    		List<Filter> filters = getFilters(fwRequest);
    
    		if (filters == null || filters.size() == 0) {
    			if (logger.isDebugEnabled()) {
    				logger.debug(UrlUtils.buildRequestUrl(fwRequest)
    						+ (filters == null ? " has no matching filters"
    								: " has an empty filter list"));
    			}
    
    			fwRequest.reset();
    
    			chain.doFilter(fwRequest, fwResponse);
    
    			return;
    		}
                 //所有的过滤器合并成一条虚拟的过滤器链
    		VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);
               //模拟过滤器的执行流程,执行整条过滤器链
    		vfc.doFilter(fwRequest, fwResponse);
    	}
    
    private static class VirtualFilterChain implements FilterChain {
    		private final FilterChain originalChain;
    		private final List<Filter> additionalFilters;
    		private final FirewalledRequest firewalledRequest;
    		private final int size;
    		private int currentPosition = 0;
    
    		private VirtualFilterChain(FirewalledRequest firewalledRequest,
    				FilterChain chain, List<Filter> additionalFilters) {
    			this.originalChain = chain;
    			this.additionalFilters = additionalFilters;
    			this.size = additionalFilters.size();
    			this.firewalledRequest = firewalledRequest;
    		}
    
    		@Override
    		public void doFilter(ServletRequest request, ServletResponse response)
    				throws IOException, ServletException {
    			if (currentPosition == size) {
    				if (logger.isDebugEnabled()) {
    					logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)
    							+ " reached end of additional filter chain; proceeding with original chain");
    				}
    
    				// Deactivate path stripping as we exit the security filter chain
    				this.firewalledRequest.reset();
                                   执行过滤器链后,调用真实的FilterChain,完成原生过滤器的剩余逻辑
    				originalChain.doFilter(request, response);
    			}
    			else {
    				currentPosition++;
    
    				Filter nextFilter = additionalFilters.get(currentPosition - 1);
    
    				if (logger.isDebugEnabled()) {
    					logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)
    							+ " at position " + currentPosition + " of " + size
    							+ " in additional filter chain; firing Filter: '"
    							+ nextFilter.getClass().getSimpleName() + "'");
    				}
                                  //通过改变下表回调的方式,按照顺序执行每一个过滤器
    				nextFilter.doFilter(request, response, this);
    			}
    		}
    	}
    

    image-20210808132205008

    image-20210808132636043

  • 相关阅读:
    使用 HTTP 缓存机制提升系统性能
    白鹭分析
    HTML5屏幕适配标签设置
    深入了解使用egret.WebSocket
    VS2013配合EgretVS开发简单塔防游戏
    C++高级语言程序设计实验五-中国矿业大学
    C++高级语言程序设计实验四-中国矿业大学
    C++高级语言程序设计实验三-中国矿业大学
    C++高级语言程序设计实验二-中国矿业大学
    C++高级语言程序设计实验一-中国矿业大学
  • 原文地址:https://www.cnblogs.com/dalianpai/p/15114752.html
Copyright © 2020-2023  润新知