2015-12-26 10 views

Antwort

7

Die clientseitige Abmeldung ist einfach, verwerfen Sie einfach das Token, das Sie besitzen. Um eine serverseitige Abmeldefunktion bereitzustellen, muss Ihre Anwendung auf aktuell authentifizierte Clients, dh vorhandene Tokens, achten. Das "build-in" -Problem bei der tokenbasierten Authentifizierung besteht darin, dass ein veröffentlichtes Token solange gültig ist, bis es abläuft und es keine "remote invalidation" -Lösung gibt. Ihre einzige Chance besteht darin, den Zugriff auf Anfragen mit einem Token zu vermeiden, dem Sie nicht mehr vertrauen.

Sie müssen sich also jedes publizierte Token in einem Container namens token store merken.

Es gibt einige Implementierungen der TokenStore Schnittstelle, um In-Memory oder vielleicht mit einer Datenbank zu arbeiten (JdbcTokenStore). Für ein einfaches Beispiel ist die InMemoryTokenStore vollkommen ausreichend.

Um es zu verwenden, muss ein Token-Speicher wie folgt erstellt und konfiguriert werden.

Fügen Sie diese auf Ihre AuthorizationServerConfiguration:

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

Und es in der AuthorizationServerEndpointsConfigurer verwenden:

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

es hinzufügen auch auf Ihre ResourceServerConfiguration:

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

, dass fast alles. Jetzt können Sie Ihre Abmelde Funktionalität implementieren, wie Sie es brauchen, vielleicht mit einem speziellen Endpunkt, wo man nur das Token erhalten haben (n) und entferne sie aus dem Token-Speicher mit:

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

bewusst sein, auch das Entfernen Aktualisierungstoken, andernfalls (wenn nur das Zugriffstoken entfernt wird) kann der Client einen neuen mit dem Aktualisierungstoken gewinnen.

Dies ist ein Testfall nach Ihren Tests zu überprüfen, ob es funktioniert:

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

Und zumindest nur eine Empfehlung, ist eine wunderbare Test-Framework MockMvc mit der es einfach zu testen Rest Anrufe und macht für Sie kann beim Arbeiten mit dem RestTemplate die Hindernisse und den Code des Kessels beseitigen. Vielleicht möchtest du es versuchen.