web-dev-qa-db-fra.com

Comment appliquer le filtre de sécurité à ressort uniquement sur les terminaux sécurisés?

J'ai la configuration Spring Security suivante:

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

authenticationTokenFilterBean() est appliqué même sur les ordinateurs d'extrémité qui ne correspondent pas à l'expression /api/**. J'ai aussi essayé d'ajouter le code de configuration suivant

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

mais cela n'a toujours pas résolu mon problème. Comment puis-je dire à Spring Security d'appliquer des filtres uniquement aux systèmes d'extrémité correspondant à l'expression d'URI sécurisée? Je vous remercie

15
Bravo

J'ai une application avec les mêmes exigences et pour la résoudre, j'ai essentiellement limité Spring Security à un modèle de correspondance de fourmi donné (à l'aide de antMatcher) comme suit:

http.antMatcher("/api/**").authorizeRequests() //
        .anyRequest().authenticated() //
        .and()
        .addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);

Vous pouvez le lire comme suit: pour http n'appeler ces configurations que sur les requêtes correspondant au modèle ant, /api/** autorisant any request à authenticated utilisateurs andadd filterauthenticationTokenFilterBean()beforeUsernamePasswordAuthenticationFilter. Pour toutes les autres demandes, cette configuration n'a aucun effet.

18
Francisco Spaeth

Si vous utilisez le .addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);

Vous pouvez définir dans le constructeur le chemin spécifique auquel il s'appliquera:

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

La méthode requireAuthentication sera utilisée pour savoir si ce terminal a besoin d'une authentification

1
Qualaelay

Je pense avoir trouvé un moyen de le résoudre. J'ai JwtTokenAuthenticationProcessingFilter qui est un AbstractAuthenticationProcessingFilter. Je veux qu'il authentifie la demande s'il y a un jeton dans la tête mais ne bloque pas la demande en cas d'échec. Tout ce dont vous avez besoin est de réécrire ledoFilteret d'appeler lechain.doFilterpeu importe le résultat de l'authentification (l'invocation de l'unsuccessfulAuthentication est facultative). Voici une partie de mon code.

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);
    }
}
0
Shengfeng Li