一旦刷新第一个访问令牌,OIDC RP 发起的注销将不起作用

问题描述 投票:0回答:1

我正在尝试实现 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}

任何帮助表示赞赏。

spring-boot spring-security spring-oauth2
1个回答
0
投票

ID 令牌和访问令牌不是一回事。

RP发起的注销请求包含的是ID令牌,而不是访问令牌。

对于

refresh_token
流,必须在初始
offline_access
流中请求
authorization_code
范围。要使用其他令牌刷新 ID 令牌,必须使用
openid
请求来请求
offline_access
refresh_token
范围。

在您的客户端注册中,您似乎没有请求

offline_access
范围,这可能就是您期望的令牌刷新没有发生的原因。

© www.soinside.com 2019 - 2024. All rights reserved.