2016-04-11 15 views
5

Lo so, ci sono molti articoli su questo argomento, ma ho un problema e non riesco a trovare alcuna soluzione.Il logout di Spring Security non funziona - non cancella il contesto di sicurezza e l'utente autenticato esiste ancora

Ho un classico di sicurezza a molla java config:

@Configuration 
@EnableWebSecurity 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 

@Autowired 
private AuctionAuthenticationProvider auctionAuthenticationProvider; 

@Autowired 
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 
    auth.authenticationProvider(auctionAuthenticationProvider); 
} 

@Override 
protected void configure(HttpSecurity http) throws Exception { 
    http.httpBasic(); 

    ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry authorizeRequest = http.authorizeRequests(); 

    configureAdminPanelAccess(authorizeRequest); 
    configureFrontApplicationAccess(authorizeRequest); 
    configureCommonAccess(authorizeRequest); 

    http.csrf() 
     .csrfTokenRepository(csrfTokenRepository()).and() 
     .addFilterAfter(csrfHeaderFilter(), CsrfFilter.class); 

    http.logout() 
     .clearAuthentication(true) 
     .invalidateHttpSession(true); 
} 
... 
} 

Inoltre, ho due metodi controller, dove ho login/logout dalla mia applicazione web AJAX.

Quando desidero disconnettermi, prima chiamo questo metodo, che mi aspetto di cancellare le sessioni utente e cancellare tutto dal contesto di sicurezza.

@Override 
@RequestMapping(value = "/logout", method = GET, produces = APPLICATION_JSON_UTF8_VALUE) 
public ResponseEntity<Boolean> logout(final HttpServletRequest request, final HttpServletResponse response) { 
    Authentication auth = SecurityContextHolder.getContext().getAuthentication(); 
    if (auth != null){ 
     new SecurityContextLogoutHandler().logout(request, response, auth); 
    } 

    return new ResponseEntity<>(Boolean.TRUE, HttpStatus.OK); 
} 

Dopo questo ricarico il mio cliente applicazione web e ogni volta, quando viene ricaricato, controllo se l'utente è autenticato chiamando il seguente metodo di controllo:

@Override 
@RequestMapping(value = "/user", method = GET, produces = APPLICATION_JSON_UTF8_VALUE) 
public ResponseEntity<UserDetails> user() { 
    Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 
    if (principal instanceof UserDetails) { 
     return new ResponseEntity<>((UserDetails) principal, HttpStatus.OK); 
    } 

    return null; 
} 

e qui mi away ricevo l'ultimo utente autenticato. Sembra che nel precedente metodo di disconnessione, il logout di Spring non funzioni.

Tenete a mente che ho cercato di effettuare il logout con il seguente codice, senza alcun successo:

@Override 
    @RequestMapping(value = "/logout", method = GET, produces = APPLICATION_JSON_UTF8_VALUE) 
    public ResponseEntity<Boolean> logout(final HttpServletRequest request) { 
    try { 
     request.logout(); 

     return new ResponseEntity<>(Boolean.TRUE, HttpStatus.OK); 
    } catch (ServletException ex) { 
     if (LOG.isDebugEnabled()) { 
      LOG.debug("There is a problem with the logout of the user", ex); 
     } 
    } 

Sei una vaga idea di quello che mi manca nel mio config e il processo di logout?

risposta

18

Dalla tua domanda, vedo che stai cercando di creare il tuo logout personale e stai anche provando a usare il logout predefinito di primavera. Ti consiglio di scegliere un metodo solo se non li ho mixati. Ci sono due modi in cui posso mostrarti logout dalla primavera:

primo: di default di logout di sicurezza primavera

.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")) 
.logoutSuccessUrl("/logout.done").deleteCookies("JSESSIONID") 
.invalidateHttpSession(true) 

da esempio di cui sopra, si dovrebbe solo bisogno di chiamare il /logout URL ogni volta che volete logout dell'utente. Non è necessario creare alcun @Controller per gestire tale disconnessione, ma spring aiuterà a disconnettere l'utente. Puoi anche aggiungere altre cose che vuoi invalidare qui.

Secondo: Proggrammatically disconnettersi

@RequestMapping(value = {"/logout"}, method = RequestMethod.POST) 
public String logoutDo(HttpServletRequest request,HttpServletResponse response){ 
HttpSession session= request.getSession(false); 
    SecurityContextHolder.clearContext(); 
     session= request.getSession(false); 
     if(session != null) { 
      session.invalidate(); 
     } 
     for(Cookie cookie : request.getCookies()) { 
      cookie.setMaxAge(0); 
     } 

    return "logout"; 
} 

Se si utilizza questo logout, voi non necessario includere il primo metodo in config sicurezza primavera. Utilizzando questo metodo, è possibile aggiungere azioni aggiuntive da fare prima e dopo il logout fatto. Per utilizzare questo logout, basta chiamare l'url /logout e l'utente verrà disconnesso manualmente. Questo metodo invaliderà la sessione, azzererà il contesto di sicurezza e i cookie.

In aggiunta per il secondo metodo, se si utilizza RequestMethod.POST, è necessario includere la chiave csrf come post. Il modo alternativo è creare un modulo con la chiave csrf di input nascosta. Questo è un esempio di auto generato link per uscire con jQuery:

$("#Logout").click(function(){ 
    $form=$("<form>").attr({"action":"${pageContext.request.contextPath}"+"/logout","method":"post"}) 
    .append($("<input>").attr({"type":"hidden","name":"${_csrf.parameterName}","value":"${_csrf.token}"})) 
    $("#Logout").append($form); 
    $form.submit(); 
}); 

Hai solo bisogno di creare collegamento ipertestuale <a id="Logout">Logout</a> di usarlo.

Se si utilizza RequestMethod.GET, è sufficiente includere una chiave CSRF come parametro in voi link come questo:

<a href="${pageContext.request.contextPath}/logout?${_csrf.parameterName}=${_csrf.token}">Logout</a> 

Questo è tutto, spero che il suo aiuto.

+1

Ciao, Freezy. In realtà, avevi ragione - ho mescolato entrambi i modi di configurazione. Quello che faccio è stato rimuovere solo il codice dal mio SecurityConfig relativo al logout e mantenere l'attuale implementazione del controller. Ora funziona correttamente. Grazie – Streetsouls

+0

ho provato il primo metodo ma non funziona ... –

+0

Come Black Swan, prima richiesta di metodo con POST o GET e con o senza controllo CSRF, mi reindirizza ma sono ancora loggato :(qualsiasi idea in cima alle tue menti? – Alex

0

Questo vi aiuterà, penso clearAuthentication (vero) è sufficiente:

@Configuration 
@EnableWebSecurity 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 

.... 

    @Override 
    protected void configure(HttpSecurity http) throws Exception 
    { 
     http 
     .httpBasic() 
     .and() 
     .logout().clearAuthentication(true) 
     .logoutSuccessUrl("/") 
     .deleteCookies("JSESSIONID") 
     .invalidateHttpSession(true) 
     .and() 
Problemi correlati