programing

Spring-boot JWT 로그아웃

css3 2023. 8. 18. 22:52

Spring-boot JWT 로그아웃

저는 이 코드 https://github.com/gdongus/spring-boot-oauth-jwt-example 을 사용하며 모든 것이 완벽하게 작동하지만 로그아웃 기능을 구현하는 방법을 모르겠습니다.누가 나에게 조언을 해줄 수 있습니까?감사해요.

클라이언트 측 로그아웃은 간단합니다. 소유한 토큰을 삭제하십시오.서버 측 로그아웃 기능을 제공하려면 응용프로그램이 현재 인증된 클라이언트, 즉 기존 토큰을 인식해야 합니다.토큰 기반 인증의 "빌드인" 문제는 토큰이 게시되면 만료될 때까지 유효하고 "원격 무효화" 솔루션이 없다는 것입니다.유일한 방법은 더 이상 신뢰하지 않는 토큰으로 요청에 대한 액세스를 피하는 것입니다.

따라서 토큰 스토어라는 컨테이너에 있는 모든 게시된 토큰을 기억해야 합니다.

몇 가지 구현이 있습니다.TokenStore 내에서 (메모리내에또서는스터인이페와는함하동작께스이베이터데)JdbcTokenStore.InMemoryTokenStore충분합니다.

이를 사용하려면 토큰 저장소를 생성하고 다음과 같이 구성해야 합니다.

을 당신의 니추합다에 추가하세요.AuthorizationServerConfiguration:

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

그리고 그것을 사용합니다.AuthorizationServerEndpointsConfigurer:

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

추가할 수도 있습니다.ResourceServerConfiguration:

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

그것이 거의 전부입니다.이제 필요에 따라 로그아웃 기능을 구현할 수 있습니다. 토큰을 가져와 토큰 저장소에서 제거하기만 하면 되는 특별한 엔드포인트를 사용할 수 있습니다.

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

새로 고침 토큰도 제거해야 합니다. 그렇지 않은 경우(액세스 토큰만 제거된 경우) 클라이언트는 새로 고침 토큰으로 새 토큰을 얻을 수 있습니다.

작동 여부를 확인하기 위한 테스트에 따른 테스트 사례는 다음과 같습니다.

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

그리고 적어도 한 가지 권장 사항은 MockMvc를 사용하는 것은 RestTemplate로 작업하는 동안 장애물과 보일러 플레이트 코드를 제거할 수 있는 훌륭한 테스트 프레임워크입니다.한 번 해보시는 게 좋을 것 같아요.

로그아웃이 완료되는 즉시 액세스 토큰과 새로 고침 토큰이 인증 서버의 기본 스토리지에서 제거되므로 리소스 서버에서 액세스 토큰이 만료될 때까지만 무효화됩니다.

이 작업을 수행하려면 이벤트를 게시해야 합니다.auth-serverStream 이벤트 Spring Stream/Integration에 .

사용자가 직접 추가할 수 있습니다.LogoutHandler인증 서버에서 이 이벤트를 게시합니다.@StreamListnerSpring 클라우드 스트림을 사용하여 각 리소스 서버에서 이 이벤트를 수신할 수 있습니다.

이 로그아웃 이벤트에는 제거된 액세스 토큰과 만료되기까지 남은 시간이 포함되어야 합니다.이 이벤트의 모든 수신자는 블랙리스트에 대한 액세스 토큰을 메모리에 저장하고 수신된 액세스 토큰이 기존 블랙리스트에 있는 토큰과 일치하는 경우 리소스에 대한 액세스를 거부해야 합니다.액세스 토큰이 만료된 후에는 메모리에서 제거하기만 하면 됩니다.키를 자동으로 만료하려면 다음과 같은 방법을 사용할 수 있습니다.CacheBuilder구아바 출신

따라서, 전반적으로, AFAIK는 JWT의 특성상 액세스 토큰의 만료에 대한 솔루션을 사용할 준비가 되어 있지 않습니다.

USER_TOKEN 테이블을 생성하여 사용자가 생성한 모든 토큰을 [다중 디바이스 로그인에 유용] 보관할 수 있으며, 프론트 엔드에서 로그아웃이 호출될 경우 프론트 엔드 로컬 스토리지에서 토큰을 제거하거나 파기하고 동일한 토큰으로 /logout api를 호출합니다.그런 다음 토큰의 유효성을 검사하고 서버 코드를 입력하고 USER_TOKEN 테이블에서 해당 토큰을 삭제합니다.

따라서 다음 번에 누군가 동일한 토큰을 사용하여 API에 액세스하려는 경우 해당 토큰은 DB에 없기 때문에 유효성이 검사되지 않습니다.

그러나 누군가가 브라우저 탭을 닫는 경우 로그아웃 대신 토큰이 만료될 때까지 작동합니다.

언급URL : https://stackoverflow.com/questions/34475946/spring-boot-jwt-logout