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
。
我一直在搜索许多 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
。