首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Spring-boot JWT注销

Spring-boot JWT注销
EN

Stack Overflow用户
提问于 2015-12-27 06:42:43
回答 3查看 17.9K关注 0票数 17

我使用这段代码https://github.com/gdongus/spring-boot-oauth-jwt-example,一切都很完美,但我不知道如何实现注销功能。有人能给我点建议吗?谢谢。

EN

回答 3

Stack Overflow用户

发布于 2017-03-20 23:19:15

客户端注销很简单,只需丢弃您拥有的令牌即可。要提供服务器端注销功能,您的应用程序必须知道当前已通过身份验证的客户端,换句话说,就是现有令牌。基于令牌的身份验证的“内置”问题是,如果一个令牌被发布,那么它在过期之前都是有效的,并且没有“远程无效”解决方案。您唯一的机会就是避免使用您不再信任的令牌来访问请求。

因此,您必须记住名为token store的容器中发布的每个令牌。

有一些TokenStore接口的实现可以在内存中工作,也可以与数据库(JdbcTokenStore)一起工作。举个简单的例子,InMemoryTokenStore是完全足够的。

要使用它,必须创建并配置令牌存储,如下所示。

将此代码添加到您的AuthorizationServerConfiguration

代码语言:javascript
复制
@Bean
public InMemoryTokenStore tokenStore() {
    return new InMemoryTokenStore();
}

并在AuthorizationServerEndpointsConfigurer中使用它

代码语言:javascript
复制
@Override
public void configure(AuthorizationServerEndpointsConfigurer configurer) throws Exception {
    configurer.authenticationManager(authenticationManager);
    configurer.userDetailsService(userDetailsService);
    configurer.accessTokenConverter(accessTokenConverter());
    configurer.tokenStore(tokenStore());
}

也将其添加到您的ResourceServerConfiguration

代码语言:javascript
复制
@Autowired
private InMemoryTokenStore inMemoryTokenStore;
...
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
    resources.resourceId("resource").tokenStore(inMemoryTokenStore);
}

这几乎就是全部了。现在,您可以根据需要实现注销功能,可能需要使用一个特殊的端点,您只需使用以下命令获取令牌并将其从令牌存储中删除:

代码语言:javascript
复制
inMemoryTokenStore.removeAccessToken(accessToken);
inMemoryTokenStore.removeRefreshToken(refreshToken);

请注意,还要删除刷新令牌,否则(如果仅删除了访问令牌)客户端将能够获得具有刷新令牌的新令牌。

下面是一个测试用例,根据您的测试来验证它是否正常工作:

代码语言:javascript
复制
@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是一个很棒的测试框架,它使得测试rest调用变得很容易,并且您可以在使用RestTemplate时消除障碍和样板代码。也许你想试一试。

票数 14
EN

Stack Overflow用户

发布于 2018-04-03 23:05:17

由于一旦注销完成,访问令牌和刷新令牌都将从身份验证服务器上的底层存储中删除,我们只需担心访问令牌在资源服务器中失效,直到访问令牌过期

为此,您需要在注销完成后立即通过Spring Stream/Integration从auth-server发布一个事件,并使所有令牌受众实例都订阅logout事件

您可以添加您自己的LogoutHandler,用于从身份验证服务器发布此事件。可以使用来自Spring cloud stream的@StreamListner在每个资源服务器上侦听此事件

此注销事件必须包含已删除的访问令牌&过期前的剩余时间。此事件的所有接收者必须将内存中的这些访问令牌存储到黑名单中&如果接收到的访问令牌与任何现有的黑名单令牌匹配,请确保它们拒绝对资源的访问。访问令牌过期后,只需将其从内存中删除即可。要自动使密钥过期,您可以使用类似CacheBuilder from guava的命令

因此,总的来说,由于JWT的性质,AFAIK没有现成的访问令牌过期解决方案

票数 1
EN

Stack Overflow用户

发布于 2020-09-22 17:10:05

因此,如果下一次有人想要使用相同的令牌访问API,该令牌将不会被验证,因为它不存在于数据库中。

但如果有人关闭浏览器选项卡,而不是注销,那么令牌将一直有效,直到过期。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34475946

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档