Spring 安全性:如何在注销时撤销刷新令牌?

Spring Security: How to revoke a refresh token on log-out?

我一直在搜索许多 SO 答案、Git 问题等。我无法找到一种方法来仅使用 Spring 安全和在用户注销时撤销刷新令牌没有弃用的 "Spring Security OAuth" 项目。

有没有办法自动管理这个而不是我自己手动向 IdP 发出请求?

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

在 Spring 安全中打开 an issue in GitHub about the current support of the RFC7009 和自动令牌撤销后,我使用一个自定义 LogoutHandler:

实现了推荐的解决方案

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

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 配置方法中,我设置了以下内容:

@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