web-dev-qa-db-ja.com

セキュリティで保護されたエンドポイントにのみスプリングセキュリティフィルターを適用する方法は?

次のSpring Security構成があります。

_    httpSecurity
            .csrf()
            .disable()
            .exceptionHandling()
            .authenticationEntryPoint(unauthorizedHandler)
            .and()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .authorizeRequests()
            .antMatchers("/api/**").fullyAuthenticated()
            .and()
            .addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
_

authenticationTokenFilterBean()は、_/api/**_式と一致しないエンドポイントにも適用されます。また、次の構成コードを追加してみました

_@Override
public void configure(WebSecurity webSecurity) {
    webSecurity.ignoring().antMatchers("/some_endpoint");
}
_

しかし、これはまだ私の問題を解決しませんでした。セキュリティで保護されたURI式に一致するエンドポイントにのみフィルターを適用するようにSpring Securityに指示するにはどうすればよいですか?ありがとうございました

18
Bravo

.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);を使用する場合

コンストラクターで、適用する特定のパスを定義できます。

public class JwtAuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    public JwtAuthenticationFilter(AuthenticationManager authenticationManager) {
        super("/api/**");
        this.setAuthenticationManager(authenticationManager);
    }

    @Override
    protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
        return super.requiresAuthentication(request, response);
    }

RequiresAuthenticationメソッドは、そのエンドポイントが認証を必要とするかどうかを知るために使用されます

1
Qualaelay

私はそれを解決する方法を見つけたと思います。 JwtTokenAuthenticationProcessingFilterであるAbstractAuthenticationProcessingFilterがあります。頭にトークンがある場合はリクエストを認証しますが、失敗した場合はリクエストをブロックしません。必要なのは、doFilterを書き換えて、を呼び出すだけです。 chain.doFilter認証結果が何であっても(unsuccessfulAuthenticationの呼び出しはオプションです)。これが私のコードの一部です。

public class JwtTokenAuthenticationProcessingFilter extends AbstractAuthenticationProcessingFilter {

    private final TokenExtractor tokenExtractor;

    @Autowired
    public JwtTokenAuthenticationProcessingFilter(TokenExtractor tokenExtractor, RequestMatcher matcher) {
        super(matcher);
        this.tokenExtractor = tokenExtractor;
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException,
            ServletException {
        HttpServletRequest request = (HttpServletRequest) req;
        HttpServletResponse response = (HttpServletResponse) res;
        if (!this.requiresAuthentication(request, response)) {
            chain.doFilter(request, response);
        } else {
            if (this.logger.isDebugEnabled()) {
                this.logger.debug("Request is to process authentication");
            }

            boolean success = true;

            Authentication authResult = null;
            try {
                authResult = this.attemptAuthentication(request, response);
            } catch (InternalAuthenticationServiceException var8) {
                this.logger.error("An internal error occurred while trying to authenticate the user.", var8);
                success = false;
            } catch (AuthenticationException var9) {
                success = false;
            }


            if (success && null != authResult) {
                this.successfulAuthentication(request, response, chain, authResult);
            }

            // Please ensure that chain.doFilter(request, response) is invoked upon successful authentication. You want
            // processing of the request to advance to the next filter, because very last one filter
            // FilterSecurityInterceptor#doFilter is responsible to actually invoke method in your controller that is
            // handling requested API resource.
            chain.doFilter(request, response);
        }
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException {
        String tokenPayload = request.getHeader(WebSecurityConfig.AUTHENTICATION_HEADER_NAME);
        RawAccessJwtToken token = new RawAccessJwtToken(tokenExtractor.extract(tokenPayload));
        return getAuthenticationManager().authenticate(new JwtAuthenticationToken(token));
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
                                            Authentication authResult) throws IOException, ServletException {
        SecurityContext context = SecurityContextHolder.createEmptyContext();
        context.setAuthentication(authResult);
        SecurityContextHolder.setContext(context);
    }
}

4月22日更新

フィルターを登録するには、次のコードをWebSecurityConfigに追加するだけです

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private final JwtAuthenticationProvider mJwtAuthenticationProvider;

    @Autowired
    public WebSecurityConfig(JwtAuthenticationProvider jwtAuthenticationProvider) {
        this.mJwtAuthenticationProvider = jwtAuthenticationProvider;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // When multiple authentication providers are defined, the providers will be queried in the order they’re
        // declared.
        auth.authenticationProvider(mJwtAuthenticationProvider);
    }
}

コードでは、フィルターの追加に関する重要な部分のみを明らかにしました。この実装はすべて このサイト に触発されました。著者のウラジミール・スタンコビッチの詳細な説明に感謝します。

0
Shengfeng Li