Spring Security:如何在注销时撤消刷新令牌?

时间:2020-06-29 15:48:20

标签: java spring spring-security identityserver4

我一直在搜索许多SO答案,Git问题等。我无法找到一种方法,仅使用Spring Security而不使用不推荐使用的"Spring Security OAuth"项目来撤销用户注销时的刷新令牌。

有没有一种方法可以自动管理此问题,而不是由我自己手动向IdP发出请求?

我想做的是在执行注销后,在RFC7009之后使用撤销的IdP端点撤销令牌,以避免出于上下文原因和出于安全原因使用此刷新令牌。

1 个答案:

答案 0 :(得分:0)

an issue in GitHub中介绍了RFC7009的当前支持以及Spring Security中的自动令牌撤销之后,我通过使用一个自定义LogoutHandler实现了推荐的解决方案:

我在我的项目(实现LogoutHandler)中创建了以下类:

CustomLogoutHandler.java

package com.test.demo.authorization;

import org.springframework.core.env.Environment;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClient;
import org.springframework.security.oauth2.client.OAuth2AuthorizedClientService;
import org.springframework.security.oauth2.client.authentication.OAuth2AuthenticationToken;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.web.reactive.function.BodyInserters;
import org.springframework.web.reactive.function.client.WebClient;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Service
public class CustomLogoutHandler implements LogoutHandler {

    private final Environment env;
    private final OAuth2AuthorizedClientService authorizedClientService;

    public CustomLogoutHandler(Environment env, OAuth2AuthorizedClientService authorizedClientService) {
        this.env = env;
        this.authorizedClientService = authorizedClientService;
    }

    @Override
    public void logout(HttpServletRequest request, HttpServletResponse response,
                       Authentication authentication) {
        String clientRegistrationId = ((OAuth2AuthenticationToken) authentication).getAuthorizedClientRegistrationId();
        OAuth2AuthorizedClient authorizedClient = this.authorizedClientService.loadAuthorizedClient(clientRegistrationId, authentication.getName());
        revokeRefreshToken(authorizedClient.getRefreshToken().getTokenValue());
    }

    private void revokeRefreshToken(String refreshToken) {
        String revocationEndpoint = env.getProperty("spring.security.oauth2.client.registration.test.revocation-endpoint");
        String clientId = env.getProperty("spring.security.oauth2.client.registration.test.client-id");
        String clientSecret = env.getProperty("spring.security.oauth2.client.registration.test.client-secret");

        LinkedMultiValueMap map = new LinkedMultiValueMap();

        map.add("token_type_hint", "refresh_token");
        map.add("token", refreshToken);
        map.add("client_id", clientId);
        map.add("client_secret", clientSecret);

        WebClient revokeTokenWebClient = WebClient.builder()
                .baseUrl(revocationEndpoint).build();

        revokeTokenWebClient
                .post()
                .body(BodyInserters.fromMultipartData(map))
                .retrieve()
                .bodyToMono(String.class)
                .block();

        return;
    }
}

之后,在我的WebSecurityConfigurerAdapter中的configure方法中,我设置了以下内容:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
      .authorizeRequests()
      .antMatchers("/img/**", "/favicon.ico", "/logged-out", "/oauth/logout")
      .permitAll()
      .anyRequest()
      .fullyAuthenticated()
      .and()
      .logout()
      .addLogoutHandler(logoutHandler)
      .logoutSuccessHandler(oidcLogoutSuccessHandler());
}

这样做,我已经实现了注销应用程序时自动撤销refresh_token的功能。