web-dev-qa-db-ja.com

特定のURLのみにSpringSecurityキャプチャフィルターを追加する方法

特定のAPI呼び出しにキャプチャフィルターを追加する非侵襲的な方法を探しています。

私のセットアップは2つのWebSecurityConfigurerAdaptersで構成され、それぞれに1つのフィルターがあります(キャプチャフィルターではありません)。

  • 内部API ( "/ iapi"はすべての呼び出しでフィルターAを使用しますが、/ authenticateなどの一部の public 要求も無視します)
  • 外部API ( "/ eapi"はすべての呼び出しでフィルターBを使用します)

パブリック、内部API、または外部API呼び出しで、SpringSecurity関連のフィルター before を追加するにはどうすればよいですか? SecurityContextは必要ありません。リクエストヘッダーでキャプチャを確認するか、filterChain(通常のフィルター)に転送するか、手動でアクセスを拒否する必要があります。 web.xmlでフィルターを宣言しようとしましたが、依存性注入を使用できなくなります。

これが私のSpringセキュリティ構成です:

@EnableWebSecurity
public class SpringSecurityConfig {
    @Configuration
    @Order(1)
    @EnableGlobalMethodSecurity(securedEnabled = true)
    public static class InternalApiConfigurerAdapter extends WebSecurityConfigurerAdapter {

        @Autowired
        private Filter filterA;

        public InternalApiConfigurerAdapter() {
            super(true);
        }

        @Override
        public void configure(WebSecurity web) throws Exception {
            web
                    .ignoring()
                    .antMatchers("/public/**");
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .antMatcher("/iapi/**")
                    .exceptionHandling().and()
                    .anonymous().and()
                    .servletApi().and()
                    .authorizeRequests()
                    .anyRequest().authenticated().and()
                    .addFilterBefore(filterA, (Class<? extends Filter>) UsernamePasswordAuthenticationFilter.class);
        }

        @Override
        @Bean
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return authenticationManager();
        }
    }

    @Configuration
    @Order(2)
    @EnableGlobalMethodSecurity(securedEnabled = true)
    public static class ExternalApiConfigurerAdapter extends WebSecurityConfigurerAdapter {

        @Autowired
        private FilterB filterB;

        public ExternalApiConfigurerAdapter() {
            super(true);
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .antMatcher("/external/**")
                    .exceptionHandling().and()
                    .anonymous().and()
                    .servletApi().and()
                    .authorizeRequests()
                    .anyRequest().authenticated().and()
                    .addFilterBefore(filterB, (Class<? extends Filter>) UsernamePasswordAuthenticationFilter.class);
        }

        @Override
        @Bean
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return authenticationManager();
        }
    }

更新:現在、web.xmlで宣言されたフィルターを使用した作業構成があります。ただし、Springコンテキストから分離されるという欠点があるため(たとえば、Beanの自動配線がない)、Springを活用するより良いソリューションを探しています。

概要:残りの2つの問題があります。

  1. 特定のURLのみのフィルターを追加します-構成内でbeforeFilter(...)を使用すると、その構成のすべてのURLにフィルターが追加されます。 Antmatchersは機能しませんでした。/iapi/captcha /、/ external/captcha /、/ public/captcha/*のようなものが必要です。
  2. Spring Securityを完全にバイパスするパブリックAPIがあります:(web .ignoring()。antMatchers( "/ public/**");)。 Spring Securityをバイパスする必要がありますが、Spring自動配線を使用してフィルターを宣言しますが、キャプチャフィルターはステートレスな方法で呼び出しを拒否または転送するだけなので、必ずしもSpringSecurity機能とは限りません。
12
Journeycorner

UsernamePasswordAuthenticationFilterの前にフィルターAとBが挿入された作業構成が既にあるので、別のカスタムフィルターを簡単に追加できるはずです。

まず、フィルターを作成し、それをBeanとして宣言し、クラスに_@Component_で注釈を付けるか、_@Bean_クラス内の_@Configuration_として宣言します。これにより、フィルターを挿入する準備が整います。 _@Autowired_。

これで、フィルターAおよびBとして注入し、使用することができます。 Spring Securityリファレンスドキュメントの Filter Ordering セクションによると、チェーンの最初のフィルターはChannelProcessingFilterであるため、SpringSecurityフィルターの何よりも先にフィルターを挿入します。チェーン、あなたはこれをするでしょう:

_@Autowired
private CaptchaFilter captchaFilter;

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .antMatcher("/iapi/**")
            .addFilterBefore(captchaFilter, (Class<? extends Filter>) ChannelProcessingFilter.class)
            .addFilterBefore(filterA, (Class<? extends Filter>) UsernamePasswordAuthenticationFilter.class)
            .authorizeRequests()
                .anyRequest().authenticated();
    }
_

ちなみに、exceptionHandling()anonymous()servletApi()は、WebSecurityConfigurerAdapterを拡張するときに、anonymous()実際に構成の詳細を指定する場合は、 HttpSecurity javadoc

SpringSecurityの「エントリポイント」であるDelegatingFilterProxyは引き続きフィルターの前に実行されますが、このコンポーネントはチェーンの最初のフィルター(この場合はCaptchaFilter)にのみ要求を委任することに注意してください。したがって、SpringSecurityの他の何よりも先にフィルターを実行することになります。

ただし、DelegatingFilterProxyの前にキャプチャフィルターを実行する必要がある場合は、Spring Security構成で実行する方法がないため、_web.xml_ファイルで宣言する必要があります。


更新:他の構成にキャプチャフィルターを含めたくない場合は、いつでも3番目の構成を追加でき、構成クラスは次のようになります。

_@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SpringSecurityConfig {

    @Configuration
    @Order(1)
    public static class CaptchaApiConfigurerAdatper extends WebSecurityConfigurerAdapter {

        @Autowired
        private CaptchaFilter captchaFilter;

        public CaptchaApiConfigurerAdatper() {
            super(true);
        }

        @Override
        public void configure(WebSecurity web) throws Exception {
            web
                    .ignoring()
                    .antMatchers("/public/**");
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                    .requestMatchers()
                        .antMatcher("/iapi/captcha**")
                        .antMatcher("/external/captcha**")
                        .and()
                    .addFilterBefore(captchaFilter, (Class<? extends Filter>) ChannelProcessingFilter.class)
                    .authorizeRequests()
                        .anyRequest().authenticated();
        }
    }            

    @Configuration
    @Order(2)
    public static class InternalApiConfigurerAdapter extends WebSecurityConfigurerAdapter {

        // ommiting code for the sake of clarity
    }

    @Configuration
    @Order(3)
    public static class ExternalApiConfigurerAdapter extends WebSecurityConfigurerAdapter {

         // ommiting code for the sake of clarity
    }
_

ちなみに、別のヒントとして、特定の構成以外のすべての一般的な構成を、@EnableGlobalMethodSecurity(securedEnabled = true) AuthenticationManager、WebSecurityなどのメインクラスにリファクタリングして、パブリックのセキュリティをスキップできますが、メインクラスは何も拡張していないので、メソッド宣言を_@Autowire_する必要があります。

WebSecurityには1つの問題がありますが、_/public/**_を無視している場合は、HttpSecurityと_/public/captcha**_のマッチャーは無視されるので、そうすべきではありません。 WebSecurityをリファクタリングし、CaptchaConfigクラスで異なるパターンを使用して、重複しないようにします。

7
saljuama