2010-07-26 21 views
14

Sto utilizzando Spring Security per proteggere le richieste HTTP su un sito web. L'utilizzo principale è per proteggere le pagine in modo tale che l'utente venga reindirizzato alla pagina di accesso quando tenta di accedere a tali pagine.Filtro personalizzato sicurezza Spring (Cambia password)

Tuttavia, ho un ulteriore requisito. Nel mio modello, posso segnalare la password di un utente come temporanea in modo tale che, quando accedono correttamente, dovrebbero essere automaticamente costretti a cambiare la loro password. Una volta che la password è cambiata, dovrebbero essere poi inoltrati alla pagina a cui stavano originariamente cercando di accedere.

Qualcuno ha utilizzato Spring Security per questo scopo? Devo creare il mio filtro personalizzato?

Grazie,

Andrew

risposta

18

In primavera Security 3.0 è possibile implementare una consuetudine AuthenticationSuccessHandler.

In questo gestore è possibile reindirizzare un utente con password temporanea alla pagina di modifica della password anziché alla pagina richiesta in origine. Dopo aver cambiato la password, è possibile reindirizzare l'utente alla pagina originariamente richiesta utilizzando SavedRequestAwareAuthenticationSuccessHandler, che è l'implementazione del gestore predefinito.

+0

Grazie per questo. Posso fare la prima parte abbastanza facilmente, ma non sono sicuro di cosa intendi per "reindirizzare l'utente a ... utilizzando SavedRequestAware AuthenticationSuccessHandler". Come reindirizzare a un gestore? – DrewEaster

+0

@dewzilla: ho aggiunto il campione di come potrebbe apparire come (con regolatore di Spring MVC per il cambiamento della password, non testato). – axtavt

+2

In realtà è controintuitivo controllare la scadenza della password nel gestore di successo dell'autenticazione, vero? Non dovresti essere in grado di autenticarti se la password è scaduta. Controlla la risposta fornita da @jyore. – Octavian

6

Sì, l'ho fatto con un filtro ForceChangePasswordFilter. Perché se l'utente digita l'url a mano può ignorare il modulo di cambio password. Con il filtro la richiesta viene sempre intercettata.

+0

ti interessa condividere il tuo codice? – Jonathan

+1

Jonathan, che era molti anni fa, non ho accesso a quel codice ora. – rodrigoap

+0

rodrigoap Capisco. Condivido lo stesso sentimento che se si utilizza il gestore di successo, l'utente sarà comunque in grado di accedere ad altre pagine scrivendo l'url direttamente nella barra degli indirizzi. Ma in fondo, potresti condividere almeno l'intento all'interno del filtro? Ho provato avente un reindirizzamento all'interno del filtro e che provoca un loop di reindirizzamento infinito come quello che è menzionato qui: http://stackoverflow.com/questions/3954930/spring-security-3-0-how-do-i-specify-urls -to-che-un-custom-filtro applicato. Pubblicheremo solo una domanda a parte per questo in SO. – Jonathan

13

Un po 'in ritardo su questo, ma si spera che questo possa aiutare gli altri a trovare questo collegamento. Se si utilizza un UserDetailsService personalizzato, è possibile impostare le credenziali di UserNonExpired su false, ad esempio, per non consentire l'accesso a qualsiasi contenuto protetto finché il campo non viene impostato su true.

Fondamentalmente, quando si ha una scadenza della password, si imposta un campo nel modello utente (passwordExpired forse), e quando UserDetailsService attira l'utente, UserDetailsService utilizzerà tale valore per impostare credentialsNonExpired.

Quindi, tutto ciò che dovete fare è aggiungere qualche configurazione alla vostra applicazioneContext-security.xml per configurare i mapping delle eccezioni di autenticazione. Ciò consentirà di rilevare l'eccezione generata dalle credenziali scadute e forzare l'utente a una pagina di reimpostazione della password. Puoi inoltre catturare account bloccati e disabilitati usando un metodo simile. L'esempio di configurazione è la seguente:

applicationContext-security.xml

<beans:bean id="exceptionTranslationFilter" class="org.springframework.security.web.authentication.ExceptionMappingAuthenticationFailureHandler"> 
    <beans:property name="exceptionMappings"> 
     <beans:props>   
      <beans:prop key="org.springframework.security.authentication.BadCredentialsException">/login_error</beans:prop> 
      <beans:prop key="org.springframework.security.authentication.CredentialsExpiredException">/password_expired</beans:prop> 
      <beans:prop key="org.springframework.security.authentication.LockedException">/locked</beans:prop> 
      <beans:prop key="org.springframework.secuirty.authentication.DisabledException">/disabled</beans:prop> 
     </beans:props> 
     </beans:property> 
</beans:bean> 

<http use-expressions="true"> 
    <!-- ADD BLACKLIST/WHITELIST URL MAPPING --> 
    <form-login login-page="/login" default-target-url="/" authentication-failure-handler-ref="exceptionTranslationFilter" /> 
</http> 

Poi basta assicurarsi di avere la configurazione controller per servire quei collegamenti con il contenuto appropriato.

+2

Questa soluzione ha un inconveniente che utente credentialsNonExpired viene verificata prima che l'utente è autenticato così di rivelare che un credenziali dell'utente sono scaduto a un utente non autenticato (ad esempio un utente malintenzionato). Immagino che una tale informazione non sia così importante, ma trovo ancora la soluzione di rodrigoap con filtro migliore. –

3

Modulo di risposta molto utile jyore, era esattamente quello che stavo cercando. Nel caso in cui si stia utilizzando una classe personalizzata che implementa UserDetailsService, è possibile farlo come segue insieme alla definizione di bean sopra nel proprio applicationContext.xml. Una cosa è che, sulla base di intestazione LMC potrebbe essere necessario utilizzare <bean .... o <prop ... invece di <beans:bean ... o <beans:prop ...

import ...... 

@Service("userService") 
public class UserDetailsServiceImpl implements UserDetailsService { 

private static Logger logger = LoggerFactory 
     .getLogger(UserDetailsServiceImpl.class); 

@Autowired 
private UserDao userDao; 

@Override 
public UserDetails loadUserByUsername(String username) 
    throws UsernameNotFoundException, DataAccessException , CredentialsExpiredException ,BadCredentialsException , 
    LockedException , DisabledException , UsernameNotFoundException 
{ 
    User user = userDao.getUserByUsername(username); 
    System.out.println("User Found"); 

    if(user == null){ 
     // System.out.println("User Not Found"); 
     logger.error("User Not Found"); 
     throw new UsernameNotFoundException(username + " is not found."); 
    } 

    if(user.isEnabled() == false){ 
    // System.out.println("User not enabled"); 
    logger.error("User not enabled"); 
     throw new DisabledException("User not enabled"); 
    } 

    if(user.isLocked() == true){ 
     //System.out.println("User is Locked"); 
     logger.error("User is Locked"); 
      throw new LockedException("User is Locked"); 
     } 
    if(user.isPasswordExpired() == true){ 
     // System.out.println("Password Expired"); 
     logger.error("Password Expired"); 
     throw new CredentialsExpiredException("Password Expired"); 
    } 

    return user; 
    } 
} 
+0

il problema è che UserDetailsService viene chiamato prima che la password sia selezionata. –

Problemi correlati