我正在尝试实现 RP 发起的注销,如 docs 中所述。
我有一个 SPA、一个充当 (BFF) 的网关和一个 Spring 授权服务器(灵感来自 ch4mpy 的示例演示)。
流程如下:SPA 向网关的 /logout 发送 get 请求,网关隐式调用授权服务器以获取 open-id-token 和注销 url,然后从 SPA 获取位置标头的响应和 href。
如果访问令牌在我注销之前没有更改,则一切正常。
但就我而言,我为访问令牌配置了较短的生命周期,并配置了刷新令牌授予类型来刷新它。 当我刷新访问令牌时,我看到存储在 AS 中的 open-id-token 正在更改(属性“nonce”消失,并且“exp”和“iat”不一样)。
我的问题是,如果访问令牌至少刷新一次,当我调用注销时,我可以看到我收到的 open-id-token 是第一个生成的(带有“nonce”和第一个值) “exp”和“iat”),而不是更新的。
当然,我在 AS 中的注销会在 OidcLogoutAuthentificationProvider.authenticate 中引发异常,因为数据库中没有匹配的 open-id-token。
一些背景:我正在使用 spring-boot 3.1.4。
AS:
OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
http.cors(withDefaults())
.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
.oidc(withDefaults());
RegisteredClient client = RegisteredClient.withId("1")
.clientId(clientId)
.clientSecret(clientSecret)
.clientAuthenticationMethod(ClientAuthenticationMethod.CLIENT_SECRET_BASIC)
.redirectUri(gatewayUri + "/login/oauth2/code/myoauth2")
.postLogoutRedirectUri(gatewayUri + "/ui/login")
.authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
.authorizationGrantType(AuthorizationGrantType.REFRESH_TOKEN)
.scope(OidcScopes.OPENID)
.scope(OidcScopes.PROFILE)
.tokenSettings(TokenSettings.builder()
.accessTokenTimeToLive(Duration.ofMinutes(2))
.refreshTokenTimeToLive(Duration.ofHours(4))
.build())
.build();
最好的朋友:
http.oauth2Login(login -> {
login.authenticationSuccessHandler(new RedirectServerAuthenticationSuccessHandler("/ui/login?success=true"));
login.authenticationFailureHandler(new RedirectServerAuthenticationFailureHandler("/ui/login?success=fail"));
})
.logout(logout -> logout.logoutSuccessHandler(new CustomLogoutSuccessHandler(clientRegistrationRepository, postLogoutRedirectUri)));
static class CustomLogoutSuccessHandler implements ServerLogoutSuccessHandler {
private final OidcClientInitiatedServerLogoutSuccessHandler delegate;
public CustomLogoutSuccessHandler(ReactiveClientRegistrationRepository clientRegistrationRepository, String postLogoutRedirectUri) {
this.delegate = new OidcClientInitiatedServerLogoutSuccessHandler(clientRegistrationRepository);
this.delegate.setPostLogoutRedirectUri(postLogoutRedirectUri);
}
@Override
public Mono<Void> onLogoutSuccess(WebFilterExchange exchange, Authentication authentication) {
return delegate.onLogoutSuccess(exchange, authentication)
.then(Mono.fromRunnable(() -> {
exchange.getExchange()
.getResponse()
.setStatusCode(HttpStatus.ACCEPTED);
}));
}
}
spring:
security:
oauth2:
client:
provider:
spring:
issuer-uri: ${backend-uri}
registration:
spring:
provider: spring
client-id: ${client-id}
client-secret: ${client-secret}
authorization-grant-type:
- authorization_code
- refresh_token
redirect-uri: ${gateway-uri}/login/oauth2/code/myoauth2
scope:
- openid
- profile
resourceserver:
jwt:
issuer-uri: ${backend-uri}
任何帮助表示赞赏。
ID 令牌和访问令牌不是一回事。
RP发起的注销请求包含的是ID令牌,而不是访问令牌。
对于
refresh_token
流,必须在初始 offline_access
流中请求 authorization_code
范围。要使用其他令牌刷新 ID 令牌,必须使用 openid
请求来请求 offline_access
和 refresh_token
范围。
在您的客户端注册中,您似乎没有请求
offline_access
范围,这可能就是您期望的令牌刷新没有发生的原因。