1. ホーム
  2. ジャワ

springSecurityセキュリティフレームワークの学習と原則の解釈

2022-02-24 01:46:30

最近、会社のプロジェクトでspring security frameworkを使ったので、勉強する機会があったのですが、私の会社のプロジェクトはspringbootスプリングブートバージョン1.59を使って構築されています

スプリングセキュリティ バージョン 4.2.3

   (理解の不正確な点があればご指摘いただければと思います)

目次

I. Springセキュリティフレームワークの紹介

 1. はじめに

 2、フレームワークの原理

 3、フレームワークのコアコンポーネント

2. カスタムセキュリティ設定のためのロードメカニズム

1. 前提条件 自社のビジネスニーズに合わせて

2, WebSecurityConfigurationクラス

3、AbstractSecurityBuilderクラス

4、Configurerをフィルタに変換する例

3. ユーザーログイン認証・認可処理


I. Springセキュリティフレームワークの紹介

     1. はじめに

           Springベースのエンタープライズアプリケーションのための宣言的なセキュリティアクセス制御ソリューションを提供するセキュリティフレームワーク(簡単に言うとアクセス制御)、アプリケーションセキュリティにはユーザー認証とユーザー認可の両方が含まれます。ユーザー認証とは、ユーザーがシステムの正当な主体であるかどうか、つまりシステムにアクセスできるかどうかを確認することです。ユーザー認証では、一般的にユーザー名とパスワードの入力が必要である。システムは、ユーザー名とパスワードを検証し、認証プロセスを完了する。ユーザー認証とは、ユーザーがある操作を実行する権限を持っていることを確認することです。システムにおいて、異なるユーザーは異なる権限を持っています。例えば、あるファイルに対して、あるユーザーは読み取ることだけができ、他のユーザーは変更することができます。一般に、システムは異なるユーザーに異なる役割を割り当て、各役割は一連の権限に対応する。   スプリングセキュリティの主なコア機能は認証と認可であり、アーキテクチャはこの2つのコア機能に基づいている。

     2. フレームワークの原則


        以下はその主なフィルターです。 

  1.         WebAsyncManagerIntegrationFilter 
  2.         SecurityContextPersistenceFilter 
  3.         ヘッダーライターフィルタ 
  4.         CorsFilter 
  5.         ログアウトフィルター
  6.         RequestCacheAwareFilter
  7.         SecurityContextHolderAwareRequestFilter
  8.         匿名認証フィルター
  9.         セッション管理フィルタ
  10.         ExceptionTranslationFilter
  11.         FilterSecurityInterceptor
  12.         ユーザー名・パスワード認証フィルター
  13.         基本認証フィルター

     3, フレームワークのコアコンポーネント

  1.       SecurityContextHolder: SecurityContextへのアクセスを提供します。
  2.       SecurityContext,: Authenticationオブジェクトとその他必要と思われる情報を保持します。
  3.       複数のAuthenticationProviderを含むことができるAuthenticationManager
  4.       ProviderManager オブジェクトは、AuthenticationManager インターフェースの実装クラスである。
  5.       AuthenticationProvider は、認証操作を行うためのメインクラスです 認証操作を行うために authenticate() メソッドを呼び出します。
  6.       Authentication: Spring Securityのメソッドの認証本体
  7.       GrantedAuthority: 認証対象に対するアプリケーションレベルの認可。
  8.      UserDetails: Authenticationオブジェクトを構築するために必要な情報で、カスタマイズ可能です。
  9.       UserDetailsService: ユーザ名でUserDetailsオブジェクトを構築し、ユーザ名でloadUserByUsernameしてUserDetailオブジェクトを取得(ここはデータベース、xml、キャッシュアクセスなど独自のビジネス実装でカスタマイズ可能)。           


II. カスタムセキュリティ設定のためのロードメカニズム

    1. 前提条件 自社のビジネスニーズに基づくもの

SpringSecrityセキュリティフレームワークの理解については、以下を参照してください。 セキュリティフレームワークspringSecurityの紹介

springSecurityフレームワークのカスタム設定クラスはWebSecurityConfigurerAdapterを継承し、configureメソッドをオーバーライドしていますが、カスタムクラスがどのように読み込まれて、どのように動作するのかが不明なので、ここではステップバイステップでデバッグして理解することにしましょう。

実は、このクラスを実装した後、Web コンテナの起動処理で、クラスのインスタンスオブジェクトが WebSecurityConfiguration クラスによって処理されるのです。

@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private AccessDeniedHandler accessDeniedHandler;

    @Autowired
    private CustAuthenticationProvider custAuthenticationProvider;

    // roles admin allow to access /admin/**
    // roles user allow to access /user/**
    // custom 403 access denied handler
    // Override the configure() method to set different access rights for different URLs
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/home", "/about","/img/*").permitAll()
                .antMatchers("/admin/**","/upload/**").hasAnyRole("ADMIN")
                .antMatchers("/order/**").hasAnyRole("USER","ADMIN")
                .antMatchers("/room/**").hasAnyRole("USER","ADMIN")
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginPage("/login")
                .permitAll()
                .and()
                .logout()
                .permitAll()
                .and()
                .exceptionHandling().accessDeniedHandler(accessDeniedHandler);
    }

    // create two users, admin and user
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {

// auth.inMemoryAuthentication()
// .withUser("user").password("user").roles("USER")
// .and()
// .withUser("admin").password("admin").roles("ADMIN");

// auth.jdbcAuthentication()

        auth.authenticationProvider(custAuthenticationProvider);
    }



  2. WebSecurityConfiguration クラス

@Configuration
public class WebSecurityConfiguration implements ImportAware, BeanClassLoaderAware {
    private WebSecurity webSecurity;
    private Boolean debugEnabled;
    private List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers;
    private ClassLoader beanClassLoader;
   
   ... Omit some code

    @Bean(
        name = {"springSecurityFilterChain"}
    )
    public Filter springSecurityFilterChain() throws Exception {
        boolean hasConfigurers = this.webSecurityConfigurers ! = null
         && !this.webSecurityConfigurers.isEmpty();
        if(!hasConfigurers) {
            WebSecurityConfigurerAdapter adapter = (WebSecurityConfigurerAdapter)
            this.objectObjectPostProcessor
              .postProcess(new WebSecurityConfigurerAdapter() {
            });
            this.webSecurity.apply(adapter);
        }

        return (Filter)this.webSecurity.build();
    }

  
    
    /*1, first execute the method will be our custom springSecurity configuration instance
       (there may be a default system configuration instance about security) The configuration instance contains our custom business privilege control configuration information
       into the object's list array in the webSecurityConfigurers
       Use the @Value annotation to inject the instance object as a formal parameter
     */   
 @Autowired(
        required = false
    )
    public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> 
    objectPostProcessor,
   @Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") 
  List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers) 
throws Exception {
    
    // Create a webSecurity object    
    this.webSecurity = (WebSecurity)objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));
        if(this.debugEnabled ! = null) {
            this.webSecurity.debug(this.debugEnabled.booleanValue());
        }

        // Sort all instances of the configuration class
        Collections.sort(webSecurityConfigurers, WebSecurityConfiguration.AnnotationAwareOrderComparator.INSTANCE);
        Integer previousOrder = null;
        Object previousConfig = null;


        // Iterate over all instances of the configuration class to determine if the order must be unique
        Iterator var5;
        SecurityConfigurer config;
        for(var5 = webSecurityConfigurers.iterator(); var5.hasNext(); previousConfig = config) {
            config = (SecurityConfigurer)var5.next();
            Integer order = Integer.valueOf(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;
        }


        // Add all configuration instances to the created webSecutity object
        var5 = webSecurityConfigurers.iterator();

        while(var5.hasNext()) {
            config = (SecurityConfigurer)var5.next();
            this.webSecurity.apply(config);
        }
        //put the webSercurityConfigures instance into the webSecurityConfigurers property of this object
        this.webSecurityConfigurers = webSecurityConfigurers;
    }

   
}


  2.1. setFilterChainProxySecurityConfigurer() メソッド

値("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}")を指定します。リスト<SecurityConfigurer<フィルタ, WebSecurity>> webSecurityConfigurers

   このパラメータ webSecurityConfigurers は、すべての構成インスタンスをこのフォームパラメータに配置します。

このメソッドの主な実行内容は次のとおりです。

     1. webSecurity オブジェクトを作成する

     2、主に設定インスタンスの順序をチェックした(順序がユニークでなければエラーを報告する)。

     3, すべてのコンフィギュレーションインスタンスは webSecurity オブジェクトに格納され、ここで コンフィギュレーション・インスタンスには、カスタム・ビジネスの許可制御設定情報が含まれています。

2.2. springSecurityFilterChain() メソッド

   springSecurityFilterChain()メソッドを呼び出すと、前のメソッドでwebSecurityConfigurersを取得したかどうかを判断し、取得していなければWebSecurityConfigurerAdapterインスタンスを作成してwebsecurityに追記します。その後、websecurity の build メソッドが呼び出されます。実際に呼び出されるのは websecurity の親クラスである AbstractSecurityBuilder の build メソッドで、最終的に springSecurityFilterChain という名前のフィルターチェーンが返されます。内部にはたくさんのFilterがあります(springSecurityは実際にたくさんのFilterに依存して、許可制御のセキュリティフレームワークを実現するためにURLをインターセプトしています)

3、AbstractSecurityBuilderクラス

public abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O> {
    private AtomicBoolean building = new AtomicBoolean();
    private O object;

  

    // call build method to return the filter chain, or call SecurityBuilder's dobuild() method

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

   //... Omit some code
}


  3.1 サブクラスの doBuild() メソッドの呼び出し

public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBuilder<O>> extends AbstractSecurityBuilder<O& gt; {
    private final Log logger;
    private final LinkedHashMap<Class<? extends SecurityConfigurer<O, B>>, List<SecurityConfigurer<O, B>>> configurers;
    private final List<SecurityConfigurer<O, B>> configurersAddedInInitializing;
    private final Map<Class<? extends Object>, Object> sharedObjects;
    private final boolean allowConfigurersOfSameType;
    private AbstractConfiguredSecurityBuilder.BuildState buildState;
    private ObjectPostProcessor<Object> objectPostProcessor;


    //doBuild() core methods init(),configure(),perFormBuild()
    protected final O doBuild() throws Exception {
        LinkedHashMap var1 = this.configurers;
        synchronized(this.configurers) {
            this.buildState = AbstractConfiguredSecurityBuilder.BuildState.INITIALIZING;
            this.beforeInit();
            this.init();
            this.buildState = AbstractConfiguredSecurityBuilder;
            this.beforeConfigure();
            this.configure();
            this.buildState = AbstractConfiguredSecurityBuilder;
            O result = this.performBuild();
            this.buildState = AbstractConfiguredSecurityBuilder;
            return result;
        }
    BUILT; return result; }

    protected abstract O performBuild() throws Exception;
    
    // call init method call the configuration class WebSecurityConfigurerAdapter init() method
    private void init() throws Exception {
        Collection<SecurityConfigurer<O, B>> configurers = this.getConfigurers();
        Iterator var2 = configurers.iterator();

        SecurityConfigurer configurer;
        while(var2.hasNext()) {
            configurer = (SecurityConfigurer)var2.next();
            configurer.init(this);
        }

        var2 = this.configurersAddedInInitializing.iterator();

        while(var2.hasNext()) {
            configurer = (SecurityConfigurer)var2.next();
            configurer.init(this);
        }

    }

    private void configure() throws Exception {
        Collection<SecurityConfigurer<O, B>> configurers = this.getConfigurers();
        Iterator var2 = configurers.iterator();

        while(var2.hasNext()) {
            SecurityConfigurer<O, B> configurer = (SecurityConfigurer)var2.next();
            configurer.configure(this);
        }

    }

    private Collection<SecurityConfigurer<O, B>> getConfigurers() {
        List<SecurityConfigurer<O, B>> result = new ArrayList();
        Iterator var2 = this.configurers.values().iterator();

        while(var2.hasNext()) {
            List<SecurityConfigurer<O, B>> configs = (List)var2.next();
            result.addAll(configs);
        }

        return result;
    }

    //... Omitting some code
}


3.2 まず、このクラスの init() メソッドを呼び出す

ビルド処理は大きく分けて、init->configure->peformBuildの3つのステップに分けられます。 

  • 1 つの init メソッドは 2 つのことを行います。1 つは getHttp() メソッドを呼び出して http インスタンスを取得し、 web.addSecurityFilterChainBuilder メソッドを介して WebSecurity securityFilterChainBuilders プロパティに割り当てられたインスタンスを取得します。2 つ目は WebSecurity の postBuildAction を付加し、構築完了後 FilterSecurityInterceptor オブジェクトが http から取得されて WebSecurity に割り当てられるというものです。 
  • 2 getHttp()メソッド、このメソッドは、例外処理()メソッドはExceptionHandlingConfigurerを、セッション管理()メソッドはSessionManagementConfigurerを、セキュリティコンテキスト()メソッドはセキュリティコンテキストConfigurerオブジェクトを追加し、これらのセキュリティConfigurer固有の実装クラスが私たちのために様々な特定のフィルタを設定するよう、(ほとんどの場合)デフォルト設定を使用するとhttpSecurityに様々なセキュリティConfigurer固有の実装クラスが付加されています。
  • 3 また、getHttp()メソッドの最後にconfigure(http)を呼び出していますが、これはWebSecurityConfigurerAdapterクラスを継承した後にオーバーライドされる可能性が最も高いメソッドです。
  • 4 configure(HttpSecurity http)メソッドでは、引き続きhttpSecurityクラスにSecurityConfigurerの特定の実装クラス、例えばauthorizeRequests()メソッド ExpressionUrlAuthorizationConfigurerメソッドを追加し、formLogin()メソッドを追加しています。ExpressionUrlAuthorizationConfigurerの実装クラスは、FormLoginConfigurerオブジェクトが比較的単純であるためより重要ですが、セキュリティ認証の過程でよく使われるFilterを提供してくれるでしょう。UsernamePasswordAuthenticationFilterです。 

上記3つのメソッドが WebSecurityConfigurerAdapter クラスの init メソッドのメインロジックです。

public abstract class WebSecurityConfigurerAdapter implements 
   WebSecurityConfigurer<WebSecurity> {

    public void init(final WebSecurity web) throws Exception {
        final HttpSecurity http = this.getHttp();
        web.addSecurityFilterChainBuilder(http).postBuildAction(new Runnable() {
            public void run() {
                FilterSecurityInterceptor securityInterceptor = (FilterSecurityInterceptor)http.getSharedObject(FilterSecurityInterceptor.class);
                web.securityInterceptor(securityInterceptor);
            }
        });
    }


 protected final HttpSecurity getHttp() throws Exception {
        if(this.http ! = null) {
            return this.http;
        } else {
            DefaultAuthenticationEventPublisher eventPublisher = (DefaultAuthenticationEventPublisher)this.objectPostProcessor.postProcess(new DefaultAuthenticationEventPublisher());
       

// Add the publisher of the authenticated event
this.localConfigureAuthenticationBldr.authenticationEventPublisher(eventPublisher);
// Get one to more instances of the AuthenticationManager object for authentication processing, which will be explained later          
AuthenticationManager authenticationManager = this.authenticationManager();
            this.authenticationBuilder.parentAuthenticationManager(authenticationManager);
            Map<Class<? extends Object>, Object> sharedObjects = this.createSharedObjects();
            this.http = new HttpSecurity(this.objectPostProcessor, this.authenticationBuilder, sharedObjects);
            if(!this.disableDefaults) {
                 HttpSecurity)((HttpSecurity)((HttpSecurity)((HttpSecurity)this.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();
                ClassLoader classLoader = this.context.getClassLoader();
                List<AbstractHttpConfigurer> defaultHttpConfigurers = SpringFactoriesLoader.loadFactories(AbstractHttpConfigurer.class, classLoader);
                Iterator var6 = defaultHttpConfigurers.iterator();

                while(var6.hasNext()) {
                    AbstractHttpConfigurer configurer = (AbstractHttpConfigurer)var6.next();
                    this.http.apply(configurer);
                }
            }

            // finally call our inherited WebSecurityConfigurerAdapter in the rewritten configure()
            // initialize our business-related permission configuration rules information
            this.configure(this.http);
            return this.http;
        }
    }


 protected AuthenticationManager authenticationManager() throws Exception {
        if(!this.authenticationManagerInitialized) {
            this.configure(this.localConfigureAuthenticationBldr);
            if(this.disableLocalConfigureAuthenticationBldr) {
                this.authenticationManager = this.authenticationConfiguration.getAuthenticationManager();
            } else {
                this.authenticationManager = (AuthenticationManager)this.localConfigureAuthenticationBldr.build();
            }

            this.authenticationManagerInitialized = true;
        }

        return this.authenticationManager;
    }



}

3.3. ステップ2設定

  • configure メソッドは、WebSecurityConfigurerAdapter の configure(WebSecurity web) メソッドの呼び出しも終了します。これはデフォルトの実装では空のメソッドですが、特定のアプリケーションで特定のニーズを達成するためにオーバーライドされることがよくあります。 

3.4. ステップ3 peformBuild

  • 具体的な実装ロジックは、WebSecurity クラスにあります。 
  • このメソッドの主なタスクは、securityFilterChainBuilders プロパティにある SecurityBuilder オブジェクトを繰り返し処理し、その build メソッドを呼び出すことです。 
    securityFilterChainBuildersプロパティは、先にも述べたようにWebSecurityConfigurerAdapterクラスのinitメソッドでhttpを取得した後、WebSecurityに割り当てました。 buildメソッドは、WebSecurityConfigurerAdapterクラスのinitメソッドでhttpを取得した後、WebSecurityに割り当てました。
  •  httpSecurityのビルドメソッドは、それにフィルタを追加します。

public final class WebSecurity extends AbstractConfiguredSecurityBuilder<Filter, WebSecurity> implements SecurityBuilder<Filter& gt;, ApplicationContextAware {
    
  ... Omit some code

    // call this method to create a securityFilter filter via the securityFilterChainBuilder.build() method
    // and add it to the securityFilterChains object, wrapping it as a FilterChainProxy to return
    protected Filter performBuild() throws Exception {
        Assert.state(!this.securityFilterChainBuilders.isEmpty(), "At least one SecurityBuilder<? Typically this done by adding a @Configuration that extends WebSecurityConfigurerAdapter. More advanced users can invoke " + WebSecurity.class.getSimpleName() + ".addSecurityFilterChainBuilder directly");
        int chainSize = this.ignoredRequests.size() + this.securityFilterChainBuilders.size();
        List<SecurityFilterChain> securityFilterChains = new ArrayList(chainSize);
        Iterator var3 = this.ignoredRequests.iterator();

        while(var3.hasNext()) {
            RequestMatcher ignoredRequest = (RequestMatcher)var3.next();
            securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest, new Filter[0]));
        }

        var3 = this.securityFilterChainBuilders.iterator();

        while(var3.hasNext()) {
            SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder = (SecurityBuilder)var3.next();
            securityFilterChains.add(securityFilterChainBuilder.build());
        }

        FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
        if(this.httpFirewall ! = null) {
            filterChainProxy.setFirewall(this.httpFirewall);
        }

        filterChainProxy.afterPropertiesSet();
        Filter result = filterChainProxy;
        if(this.debugEnabled) {
            this.logger.warn("\n\n********************************************************************\n********** Security debugging is enabled. *************\n********** This may include sensitive information. *************\n********** Do not use in a production system! ********* ****\n********************************************************************\n\n");
            result = new DebugFilter(filterChainProxy);
        }

        this.postBuildAction.run();
        return (Filter)result;
    }

   
}



 4. Configurerをフィルタに変換する例

ExpressionUrlAuthorizationConfigurerの継承関係 
ExpressionUrlAuthorizationConfigurer->AbstractInterceptUrlConfigurer->AbstractHttpConfigurer->SecurityConfigurerAdapter-& gt;SecurityConfigurerを使用します。 
対応する SecurityConfigurerAdapter クラスの init メソッドは何もしない空の実装で、SecurityConfigurerAdapter クラスの configure メソッドも AbstractInterceptUrlConfigurer クラスで空の実装がオーバーライドされています。 

Abstractintercepturlconfigurer.javaのコード 

@Override  
    public void configure(H http) throws Exception {  
        FilterInvocationSecurityMetadataSource metadataSource = createMetadataSource(http);  
        if (metadataSource == null) {  
            return;  
        }  
        FilterSecurityInterceptor securityInterceptor = createFilterSecurityInterceptor(  
                http, metadataSource, http.getSharedObject(AuthenticationManager.class));  
        if (filterSecurityInterceptorOncePerRequest ! = null) {  
            securityInterceptor  
                    .setObserveOncePerRequest(filterSecurityInterceptorOncePerRequest);  
        }  
        securityInterceptor = postProcess(securityInterceptor);  
        http.addFilter(securityInterceptor);  
        http.setSharedObject(FilterSecurityInterceptor.class, securityInterceptor);  
    }  
...  
private AccessDecisionManager createDefaultAccessDecisionManager(H http) {  
        AffirmativeBased result = new AffirmativeBased(getDecisionVoters(http));  
        return postProcess(result);  
    }  
...  
private FilterSecurityInterceptor createFilterSecurityInterceptor(H http,  
            FilterInvocationSecurityMetadataSource metadataSource,  
            AuthenticationManager authenticationManager) throws Exception {  
        FilterSecurityInterceptor securityInterceptor = new FilterSecurityInterceptor();  
        securityInterceptor.setSecurityMetadataSource(metadataSource);  
        securityInterceptor.setAccessDecisionManager(getAccessDecisionManager(http));  
        securityInterceptor.setAuthenticationManager(authenticationManager);  
        securityInterceptor.afterPropertiesSet();  
        return securityInterceptor;  
    }  


4.1. このクラスのconfigureでFilterSecurityInterceptorが作成され、spring securityがデフォルトで作成してくれるAccessDecisionManagerはAffirmativeBasedであることもわかります。 
4.2、.最後に、ビルドを行うHttpSecurityクラスの最後のステップであるperformBuildを実装しているメソッドを見てみましょう。 

Httpsecurity.javaのコード 

@Override  
    protected DefaultSecurityFilterChain performBuild() throws Exception {  
        Collections.sort(filters, comparator);  
        return new DefaultSecurityFilterChain(requestMatcher, filters);  
    }  



見ての通り、このクラスは HttpSecurity に追加するセキュリティを、ソートクラス FilterComparator を使ってソートするだけで、フィルタが正しい順序で実行されることを保証しています。そして、フィルターは filterChian リターンに構築されます。先の WebSecurity の performBuild メソッドで、この戻り値は FilterChainProxy としてラップされ、WebSecurity の build メソッドの putback 値として使用されます。そこから springSecurityFilterChain という名前で springContext に登録されます(WebSecurityConfiguration の中で行います)。 
4.3. WebSecurity の performBuild メソッドの最後のステップでは、postBuildAction.run も実行されます。これは、ビルドが完了した後に何かを行うために spring security が与えてくれるフックで、例えば WebSecurityConfigurerAdapter クラスの init メソッドでは、このフックを使って WebSecurityクラスの filterSecurityInterceptor のプロパティに FilterSecurityInterceptor を割り当ててビルド完了後、次のようなことをします。

三、ユーザーログインの認証と認可の処理

      1. 完全なユーザーログインの認証と認可は、何重ものインターセプターを経由して許可制御を実現するリクエストです。Web側全体はDelegatingFilterProxy(springSecurityの委譲フィルタリングプロキシクラス)として構成されますが、これは実際のフィルタリングは実現しません。 実際のインターセプトは、スプリングコンテナが管理する個々のフィルタビーンで構成されている filterChain で実現されます。

実際のFilterChainProxyのdoFilterInternal()メソッドは、DelegatingFilterProxyのdoFilter()メソッドから以下のように呼び出されてすべてのインターセプターを取得しフィルタリングを実行します。

public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        Filter delegateToUse = this.delegate;
        if(delegateToUse == null) {
            Object var5 = this.delegateMonitor;
            synchronized(this.delegateMonitor) {
                delegateToUse = this.delegate;
                if(delegateToUse == null) {
                    WebApplicationContext wac = this.findWebApplicationContext();
                    if(wac == null) {
                        throw new IllegalStateException("No WebApplicationContext found: no ContextLoaderListener or DispatcherServlet registered?");
                    }

                    delegateToUse = this.initDelegate(wac);
                }

                this.delegate = delegateToUse;
            }
        }

// Call the doFilterInternal() method of the actual FilterChainProxy to get all the interceptors and do the filtering
        this.invokeDelegate(delegateToUse, request, response, filterChain);
    }



実際の FilterChainProxy の doFilter() メソッドを呼び出して、すべてのインターセプターを取得し、フィルタリングを実行します。

2. FilterChainProxy クラス

    最後に FilterChainProxy の doFilterInternal() メソッドを呼び出して、すべてのフィルタ・インスタンスを取得します。

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

    }

    private void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        FirewalledRequest fwRequest = this.firewall.getFirewalledRequest((HttpServletRequest)request);
        HttpServletResponse fwResponse = this.firewall.getFirewalledResponse((HttpServletResponse)response);
         // All past filters
        List<Filters> filters = this.getFilters((HttpServletRequest)fwRequest);
        if(filters ! = null && filters.size() ! = 0) {
            FilterChainProxy.VirtualFilterChain vfc = new FilterChainProxy.VirtualFilterChain(fwRequest, chain, filters);
            vfc.doFilter(fwRequest, fwResponse);
        } else {
            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);
        }
    }


  private List<Filter> getFilters(HttpServletRequest request) {
       // iterate through all matcher classes continue to get if supported
        Iterator var2 = this.filterChains.iterator();

        SecurityFilterChain chain;
        do {
            if(!var2.hasNext()) {
                return null;
            }

            chain = (SecurityFilterChain)var2.next();
        } while(!chain.matches(request));
        //go after all the filters in the match
        return chain.getFilters();
    }

上記のように、実際にはこのリクエストのすべてのフィルタを取得し、指定された順番で doFilter() メソッドをインストールします。

これは、このビジネス・リクエストに対して作者が実行するすべてのフィルタです。 

  1.     WebAsyncManagerIntegrationFilter
  2.      SecurityContextPersistenceFilter
  3.      ヘッダーライターフィルタ     
  4.      ログアウトフィルター
  5.      ユーザー名・パスワード認証フィルター
  6.      RequestCacheAwareFilter
  7.      SecurityContextHolderAwareRequestFilter
  8.      匿名認証フィルター
  9.      セッション管理フィルタ
  10.      ExceptionTranslationFilter
  11.      FilterSecurityInterceptor

springSecutityインターセプターの紹介は、以下のリンクを参照してください。

Spring Security Core Filter Chain Analysis_CatalpaFlatのブログ - CSDN Blog

Spring Security (IV) - コアフィルターのソースコード解析|プログラマDD

Spring Securityのコアとなるインターセプター - 丿少女梦丶 - 博客园

春のセキュリティ 11 フィルタ - CSDN Blog

Spring Securityコアフィルターのソースコード解析 - (three)_m0_37834471のブログ - CSDNブログ

Spring Security学習ノート - 認証制御フィルタ - Joyen.fu - Blogspot