2015-12-16 26 views
8

Sto cercando un modo non invasivo per aggiungere un filtro captcha per determinate chiamate API.Ulteriori aggiungere il filtro captcha Spring Security solo per URL specifici

La mia configurazione è costituito da due WebSecurityConfigurerAdapters con un filtro ciascuna (non il filtro captcha):

  • api interno ("/ IAPI" uso filtro A su tutte le chiamate, ma anche ignorare alcuni pubblici richieste come/autenticazione)
  • API esterna ("/ EAPI" uso filtro B per tutte le chiamate)

Ho Posso aggiungere un filtro prima del per gli articoli Spring Security, su public, interni api o chiamate api esterne? Non ho bisogno di SecurityContext, ho solo bisogno di controllare un Captcha nelle intestazioni delle richieste, inoltrare a FilterChain (filtri normali) o negare manualmente l'accesso. Ho provato a dichiarare un filtro in web.xml, ma ciò interrompe la possibilità di utilizzare l'iniezione delle dipendenze.

Qui è la mia Primavera Security Configuration:

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

Aggiornamento: Al momento ho una configurazione di lavoro con un filtro dichiarata in web.xml. Tuttavia, ha lo svantaggio di essere separato dal contesto primaverile (ad esempio, nessun autowiring di bean), quindi sto cercando una soluzione migliore che faccia leva su Spring.

Sommario: Ci sono due problemi rimanenti:

  1. aggiungere un filtro per URL specifici solo - utilizzando beforeFilter (...) all'interno di qualsiasi configurazione aggiunge un filtro a tutti gli URL di tale configurazione. Antmatcher non ha funzionato. Ho bisogno di qualcosa del genere:/iapi/captcha/,/external/captcha/,/public/captcha/*.
  2. Ho una publicap che ignora completamente Spring Security: (web .ignoring() .antMatchers ("/ public/**");). Devo bypassare Spring Security ma comunque dichiarare un filtro lì, usando Spring autowiring, ma non necessariamente Spring Security, dal momento che il mio captcha filter rifiuta o inoltra le chiamate solo in modo stateless.
+1

Si sta parlando di 'Filtro A' e' Filtro B'. Sono segnaposto per il tuo filtro captcha o hai una vera implementazione per questo? In tal caso, potresti aggiornare la tua domanda di conseguenza? –

+1

non proprio sicuro se è esattamente quello che stai cercando, ma ho trovato [questa risposta] (http://stackoverflow.com/a/11929129/4207875) a una domanda simile. Le differenze sono che aggiungono il filtro alla fine della catena e la configurazione è in XML, ma in javaconfig, anche l'http.addFilterBefore() fa il trucco. – saljuama

+0

@ksokol Sono i filtri del sistema attuale, non voglio toccarli. – Journeycorner

risposta

5

Si dispone già di una configurazione di lavoro con i filtri A e B inseriti prima di UsernamePasswordAuthenticationFilter quindi è consigliabile aggiungere un altro filtro personalizzato.

primo luogo, si crea il filtro, e dichiarare come un fagiolo, sia annotando la classe con @Component, o come @Bean all'interno di una classe @Configuration, quindi è pronto per essere iniettato con @Autowired.

Ora è possibile iniettarlo, come filtro A e B, e usarlo.Secondo la sezione Filter Ordering nella documentazione di riferimento Primavera di sicurezza, il primo filtro della catena è ChannelProcessingFilter, così al fine di inserire il filtro prima di tutto nella catena dei filtri Primavera di sicurezza, faresti questo:

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

Tra l'altro, exceptionHandling()anonymous() e servletApi() non sono necessari, perché quando si estende WebSecurityConfigurerAdapter, questi sono già inclusi, ad eccezione di anonymous() quando effettivamente specificano i dettagli di configurazione, come si afferma HttpSecurity javadoc

Tenete a mente che la sicurezza Primavera "entrypoin t ", il DelegatingFilterProxy sarà ancora eseguito prima del filtro, ma questo componente delega solo la richiesta al primo filtro della catena, che in questo caso sarebbe CaptchaFilter, quindi si eseguirà il filtro prima di qualsiasi altra cosa da Spring Security .

Ma se si desidera che il filtro captcha sia eseguito prima dello DelegatingFilterProxy, non è possibile farlo nella configurazione di Spring Security ed è necessario dichiararlo nel file web.xml.


Aggiornamento: Se non si desidera includere il filtro captcha nelle altre formazioni, si può sempre aggiungere una terza configurazione, e la classe configurazioni potrebbe essere il seguente:

@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 
    } 

A un altro consiglio, puoi rifattorizzare tutta la configurazione comune al di fuori delle configurazioni specifiche, nella classe principale, come @EnableGlobalMethodSecurity(securedEnabled = true) l'AuthenticationManager, lo WebSecurity saltare la sicurezza per il pubblico, ma per quelli visto che la classe principale non sta estendendo nulla dovresti @Autowire le dichiarazioni del metodo.

Anche se ci sarebbe stato un problema con il WebSecurity, se si sta ignorando /public/** il matcher per la HttpSecurity con /public/captcha** sarebbero ignorati, quindi credo che, non dovreste refactoring la WebSecurity e hanno un modello diverso nella classe CaptchaConfig così non si sovrappone.

+0

Scusa, ho già provato questo approccio. Userebbe quei due filtri su qualsiasi richiesta, ma ho bisogno di percorsi specifici. Inoltre, non so ancora come aggiungerli alle chiamate non di Spring Security. Ho aggiornato la mia domanda di conseguenza. Grazie per l'indicazione sulla gestione delle eccezioni, quella roba mi aiuta a capire meglio Spring Security! – Journeycorner

+0

Non c'è nulla che ti impedisca di aggiungere una terza configurazione per il filtro captcha, basta tenere a mente il '@ Ordine', aggiornerò la risposta con un esempio. – saljuama