2015-12-26 30 views

risposta

7

Il logout lato client è semplice, basta scartare il token che si possiede. Per fornire una funzionalità di disconnessione sul lato server, l'applicazione deve essere a conoscenza dei client attualmente autenticati, in altre parole, dei token esistenti. Il problema del "build-in" con l'autenticazione basata su token è che se un token è pubblicato è valido fino alla sua scadenza e non esiste una soluzione di "invalidazione remota". La tua unica possibilità è di evitare l'accesso per le richieste con un token di cui non ti fidi più.

Quindi è necessario ricordare ogni token pubblicato in un contenitore denominato token store.

Ci sono alcune implementazioni dell'interfaccia TokenStore per lavorare in-memory o magari con un database (JdbcTokenStore). Per un semplice esempio, lo InMemoryTokenStore è totalmente sufficiente.

Per utilizzarlo, un archivio di token deve essere creato e configurato come segue.

Aggiungi questo al vostro AuthorizationServerConfiguration:

@Bean 
public InMemoryTokenStore tokenStore() { 
    return new InMemoryTokenStore(); 
} 

e utilizzarlo nel AuthorizationServerEndpointsConfigurer:

@Override 
public void configure(AuthorizationServerEndpointsConfigurer configurer) throws Exception { 
    configurer.authenticationManager(authenticationManager); 
    configurer.userDetailsService(userDetailsService); 
    configurer.accessTokenConverter(accessTokenConverter()); 
    configurer.tokenStore(tokenStore()); 
} 

aggiungerlo anche al vostro ResourceServerConfiguration:

@Autowired 
private InMemoryTokenStore inMemoryTokenStore; 
... 
@Override 
public void configure(ResourceServerSecurityConfigurer resources) throws Exception { 
    resources.resourceId("resource").tokenStore(inMemoryTokenStore); 
} 

che è quasi tutto. Ora è possibile implementare la funzionalità di disconnessione come ne avete bisogno, magari con un endpoint speciale dove devi solo ottenere il token (s) e rimuoverlo dal negozio token con:

inMemoryTokenStore.removeAccessToken(accessToken); 
inMemoryTokenStore.removeRefreshToken(refreshToken); 

Essere consapevoli di rimuovere anche il Aggiorna token, altrimenti (se viene rimosso solo il token di accesso) il client è in grado di ottenerne uno nuovo con il token di aggiornamento.

Ecco un banco di prova in base alle vostre test per verificare se funziona:

@Test 
public void getUserWithValidAuth() throws Exception { 
    final HttpHeaders headers = getHttpHeader(CLIENT_USER, CLIENT_SECRET); 
    final HttpEntity<String> request = new HttpEntity<>(headers); 

    final String tokenUrl = getOAuthTokenUrl(OAUTH_TOKEN_USERNAME, OAUTH_TOKEN_PASSWORD); 
    final ResponseEntity<Object> response = restTemplate.exchange(tokenUrl, HttpMethod.POST, request, Object.class); 
    assertTrue("Did not get auth tokens!", response.getStatusCode().is2xxSuccessful()); 

    final Map result = (Map) response.getBody(); 
    final String accessTokenAsString = (String) result.get(ACCESS_TOKEN); 
    final String refreshTokenAsString = (String) result.get(REFRESH_TOKEN); 

    final String resourceUrlWithToken = "http://localhost:" + port + "/users?access_token=" + accessTokenAsString; 

    final ResponseEntity<String> userResponse = restTemplate.exchange(resourceUrlWithToken, HttpMethod.GET, null, 
      String.class); 
    assertTrue("Could not request user data!", userResponse.getStatusCode().is2xxSuccessful()); 

    final OAuth2AccessToken accessToken = inMemoryTokenStore.readAccessToken(accessTokenAsString); 
    final OAuth2RefreshToken refreshToken = inMemoryTokenStore.readRefreshToken(refreshTokenAsString); 
    inMemoryTokenStore.removeAccessToken(accessToken); 
    inMemoryTokenStore.removeRefreshToken(refreshToken); 

    try { 
     restTemplate.exchange(resourceUrlWithToken, HttpMethod.GET, null, String.class); 
     fail("Should not get here, expected 401 for request with access token!"); 
    } catch (HttpClientErrorException e) { 
     // would not be needed with MockMvc 
    } 

    final String refreshTokenUrl = REFRESH_TOKEN_URL + refreshTokenAsString; 
    try { 
     restTemplate.exchange(refreshTokenUrl, HttpMethod.POST, request, Object.class); 
     fail("Should not get here, expected 401 for request with refresh token!"); 
    } catch (HttpClientErrorException e) { 
     // would not be needed with MockMvc 
    } 
} 

E almeno solo una raccomandazione, utilizzando MockMvc è un quadro di prova impressionante che lo rende facile per testare le chiamate di riposo e si può sbarazzarsi degli ostacoli e del codice della piastra della caldaia mentre lavora con il RestTemplate. Forse vuoi fare un tentativo.

Problemi correlati