Spring Security Configuration Learning Notes

Posted by IlikeTheWeb on Sat, 11 May 2019 02:47:06 +0200

  • AbstractSecurity Web Application Initializer is used to add Delegating Filter Proxy to web containers and formulate proxy bean s named Spring Security-specific Spring Security Filter Chain:
    private void insertSpringSecurityFilterChain(ServletContext servletContext) {
        String filterName = DEFAULT_FILTER_NAME;
        DelegatingFilterProxy springSecurityFilterChain = new DelegatingFilterProxy(
                filterName);
        String contextAttribute = getWebApplicationContextAttribute();
        if (contextAttribute != null) {
            springSecurityFilterChain.setContextAttribute(contextAttribute);
        }
        registerFilter(servletContext, true, filterName, springSecurityFilterChain);
    }

This approach is usually used to configure Spring Security without web.xml in pure Spring MVC (non-Spring Boot) projects, similar to adding in web.xml:

    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
  • For Spring Boot, we don't need to use AbstractSecurity Web Application Initializer, because Security Filter AutoConfiguration adds Delegating Filter Proxy to the web container in the following ways:
    @Bean
    @ConditionalOnBean(name = DEFAULT_FILTER_NAME)
    public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration(
            SecurityProperties securityProperties) {
        DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean(
                DEFAULT_FILTER_NAME);
        registration.setOrder(securityProperties.getFilterOrder());
        registration.setDispatcherTypes(getDispatcherTypes(securityProperties));
        return registration;
    }
  • Spring Security uses Servlet's Filter mechanism, which includes Spring MVC's Dispatcher Servlet before any Servlet. So in Spring Security's eyes, Dispatcher Servlet is just a normal Servlet, which is no different from other Servlets. Therefore, Spring Security has nothing to do with Spring MVC, it can be used together or separately for other environments, but Spring Security is supported by Spring's IoC container, so you still need to configure ContextLoader Listener or use AbstractContextLoader Initializer when using it in Servelt container of non-Spring MVC.

  • There are two important configuration classes in Spring Security configuration, one is SecuirtyBuilder, which is a very generic class for building any object, and the other is SecurityConfigurator, which is used for configuring SecuirtyBuilder. WebSecurity and HttpSecurity are both subclasses of SecuirtyBuilder. WebSecurity is used to build a FilterChainProxy (a Filter) and HttpSecurity is used to build a DefaultSecurity FilterChain, which can be seen from the class definitions of both. Security Configurator is mainly used to configure HttpSecurity. Its function is to inject various filters into Default Security FilterChain, such as CorsConfigurer adding CorsFilter to HttpSecurity.

  • @ Enable Web Security is usually used on the Web Security Configurer Adapter and in conjunction with @Configuration, so that Spring Security can be enabled on the one hand, and WebSecurity Configurer Adapter can be used to configure other aspects, and the WebSecurity Configurer Adapter itself is a bean (with the @Configuration class being a bean) and can then be used by WebSecurity Configuration Configuration. The configuration is automatically injected to complete the configuration.

  • @ The most important role of Enable Web Security is to make Web Security Configuration effective through @Import. Web Security Configuration defines several Spring Security Beans, the most important of which is a bean named Spring Security FilterChain:

    @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();
    }

This spring Security Filter Chain is the bean that Spring Security finds through Delegating Filter Proxy at startup.

  • The real type of the bean named spring Security Filter Chain is FilterChain Proxy, which is also the total entry of Spring Security. FilterChain Proxy maintains several Lists of Security Filter Chain, and Security Filter Chain maintains a list of Filters. What it really does is the List of Filters of Security Filter Chain (for example, it contains Usernames Passes). Word Authentication Filter and LogoutFilter, etc. When the request comes, the matches() method of each SecurityFilterChain is invoked to determine which SecurityFilterChain to process. When the first one is found, the subsequent SecurityFilterChain will have no chance. Therefore, the SecurityFilterChain in front of the List will play a priority role. The more precise path matching should be put in front of the actual configuration. In Spring, the order of automatically injecting beans into List can be determined by @Order, that is, by adding @Order to WebSecurity Configurer Adapter, then in WebSecurity Configuration, multiple WebSecurity Configurer Adapters in the list of webSecurity Configurers have been arranged in order. By default, SecurityFilterChain can handle all requests, and when configuring the SecurityFilterChain, you can use request Matcher to filter.
    For an architectural explanation of Spring Security, please refer to Here and Here.

  • When configuring, there are two main configuration classes, one is WebSecurity, the other is HttpSecurity. There is only one WebSecurity in Spring Security and initialization is completed in WebSecurity Configuration. HttpSecurity can have more than one. A WebSecurity Configurer Adapter creates an HttpSecurity, which corresponds to a Security Filter Chain.

  • Web Security Configuration creates Web Security:

    @Autowired(required = false)
    public void setFilterChainProxySecurityConfigurer(
            ObjectPostProcessor<Object> objectPostProcessor,
            @Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
            throws Exception {
        webSecurity = objectPostProcessor
                .postProcess(new WebSecurity(objectPostProcessor));
        if (debugEnabled != null) {
            webSecurity.debug(debugEnabled);
        }

        Collections.sort(webSecurityConfigurers, AnnotationAwareOrderComparator.INSTANCE);

        Integer previousOrder = null;
        Object previousConfig = null;
        for (SecurityConfigurer<Filter, WebSecurity> config : webSecurityConfigurers) {
            Integer order = 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;
            previousConfig = config;
        }
        for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {
            webSecurity.apply(webSecurityConfigurer);
        }
        this.webSecurityConfigurers = webSecurityConfigurers;
    }
  • WebSecurity Configurer Adapter creates HttpSecurity:
    protected final HttpSecurity getHttp() throws Exception {
        if (http != null) {
            return http;
        }

        DefaultAuthenticationEventPublisher eventPublisher = objectPostProcessor
                .postProcess(new DefaultAuthenticationEventPublisher());
        localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);

        AuthenticationManager authenticationManager = authenticationManager();
        authenticationBuilder.parentAuthenticationManager(authenticationManager);
        authenticationBuilder.authenticationEventPublisher(eventPublisher);
        Map<Class<? extends Object>, Object> sharedObjects = createSharedObjects();

        http = new HttpSecurity(objectPostProcessor, authenticationBuilder,
                sharedObjects);
        if (!disableDefaults) {
            // @formatter:off
            http
                .csrf().and()
                .addFilter(new WebAsyncManagerIntegrationFilter())
                .exceptionHandling().and()
                .headers().and()
                .sessionManagement().and()
                .securityContext().and()
                .requestCache().and()
                .anonymous().and()
                .servletApi().and()
                .apply(new DefaultLoginPageConfigurer<>()).and()
                .logout();
            // @formatter:on
            ClassLoader classLoader = this.context.getClassLoader();
            List<AbstractHttpConfigurer> defaultHttpConfigurers =
                    SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, classLoader);

            for (AbstractHttpConfigurer configurer : defaultHttpConfigurers) {
                http.apply(configurer);
            }
        }
        configure(http);
        return http;
    }
  • WebSeurity is mainly used to configure requests that need to be ignored:
   @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring()
                .antMatchers("/bi/email-login/**");
    }
  • HttpSecurity is mainly used to configure filters for various functions, so when configuring Spring Security, we mainly configure HttpSecurity, such as:
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf()
                .disable()
                .authorizeRequests()
                .anyRequest()
                .authenticated();
    }
  • WebSecurity is used to configure FilterChain Proxy. There is only one FilterChain Proxy in Spring Security, that is, only one WebSeurity configuration. WebSecurity is created in the @Enable WebSecurity entry configuration WebSecurity Configuration.

  • If you don't want Spring Security to be applied to a path, you can configure it through ignoring() of WebSecurity. In fact, WebSecurity will create a Security FilterChain based on the ignoring() configuration, except that the Security FilterChain does not have any filters.

  • HttpSecurity is used for one-to-one configuration of SecurityFilterChain. A FilterChainProxy can contain multiple SecurityFilterChains, so Spring Security can have multiple HttpSecurity in configuration. HttpSecurity was created in WebSecurity Configurer Adapter, that is, a WebSecurity Configurer Adapter should configure a HttpSecurity, and then a Security Filter Chain.

  • WebSecurity Configuration implements WebSecurity Configurer Adapter interface bean s by @Autowire automatic injection at initialization. All of these WebSecurity Configurer Adapters can configure the same WebSecurity and can configure their own HttpSecurity.

  • Spring Boot configures an empty Web Security Configurer Adapter through Security AutoConfiguration, and then configures an in memory user, user name, random password through User Details Service AutoConfiguration, thereby creating a Bean of type InMemory User Details Manager. InMemory User Details Manager implements User Details Service, which is found by Spring Security's Authentication Configuration through global Auth Configurers, that is, Initialize User Details Manager Configurer/Initialize User Details Bean Manager Configurer finds User Details Service type beans in the IoC container and uses them to build a global Authentication Details Service. Application Manager. Because InitializeUser Details Bean Manager Configurer implements Global Authentication Configurer Adapter, it is automatically found in Authentication Configuration:

    @Autowired(required = false)
    public void setGlobalAuthenticationConfigurers(
            List<GlobalAuthenticationConfigurerAdapter> configurers) throws Exception {
        Collections.sort(configurers, AnnotationAwareOrderComparator.INSTANCE);
        this.globalAuthConfigurers = configurers;
    }
  • Spring Security sorts multiple filters in the Security Filter Chain through the Filter Comparator, and you can see that the default order of filters is written to death.
FilterComparator() {
        Step order = new Step(INITIAL_ORDER, ORDER_STEP);
        put(ChannelProcessingFilter.class, order.next());
        put(ConcurrentSessionFilter.class, order.next());
        put(WebAsyncManagerIntegrationFilter.class, order.next());
        put(SecurityContextPersistenceFilter.class, order.next());
        put(HeaderWriterFilter.class, order.next());
        put(CorsFilter.class, order.next());
        put(CsrfFilter.class, order.next());
        put(LogoutFilter.class, order.next());
        filterToOrder.put(
            "org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter",
                order.next());
        put(X509AuthenticationFilter.class, order.next());
        put(AbstractPreAuthenticatedProcessingFilter.class, order.next());
        filterToOrder.put("org.springframework.security.cas.web.CasAuthenticationFilter",
                order.next());
        filterToOrder.put(
            "org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter",
                order.next());
        put(UsernamePasswordAuthenticationFilter.class, order.next());
        put(ConcurrentSessionFilter.class, order.next());
        filterToOrder.put(
                "org.springframework.security.openid.OpenIDAuthenticationFilter", order.next());
        put(DefaultLoginPageGeneratingFilter.class, order.next());
        put(DefaultLogoutPageGeneratingFilter.class, order.next());
        put(ConcurrentSessionFilter.class, order.next());
        put(DigestAuthenticationFilter.class, order.next());
        filterToOrder.put(
                "org.springframework.security.oauth2.server.resource.web.BearerTokenAuthenticationFilter", order.next());
        put(BasicAuthenticationFilter.class, order.next());
        put(RequestCacheAwareFilter.class, order.next());
        put(SecurityContextHolderAwareRequestFilter.class, order.next());
        put(JaasApiIntegrationFilter.class, order.next());
        put(RememberMeAuthenticationFilter.class, order.next());
        put(AnonymousAuthenticationFilter.class, order.next());
        filterToOrder.put(
            "org.springframework.security.oauth2.client.web.OAuth2AuthorizationCodeGrantFilter",
                order.next());
        put(SessionManagementFilter.class, order.next());
        put(ExceptionTranslationFilter.class, order.next());
        put(FilterSecurityInterceptor.class, order.next());
        put(SwitchUserFilter.class, order.next());
    }
  • Spring Security's FilterChain Proxy defaults to Ordered Filter. REQUEST_WRAPPER_FILTER_MAX_ORDER-100, which is a very advanced sort. You can set the order number of the filter, such as:
security.filter-order=5

For other custom beans, you can sort them by FilterRegistration Bean. setOrder (), or by @Order:

@Order(Ordered.LOWEST_PRECEDENCE -1)
@Component
public class ABCFilter implements Filter {
  ------
} 
  • For more configuration instructions, please refer to Here and Here.

Topics: Spring xml