已解决:Keycloak + Spring Security OIDC 反向通道注销:SSO 会话最大/空闲后无法触发将 UI 重定向到 Keycloak 登录

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

我有一个配置为 Spring Security OAuth2 客户端的 Spring Boot 应用程序。我使用 Keycloak 作为我的 OIDC 提供商。我从 Spring Boot 应用程序中提供编译后的 Angular 应用程序。 Angular 应用程序每秒都会向 Spring Boot 应用程序中的 REST API 发出请求。

当用户在浏览器中的 localhost:4881 打开此应用程序时,他们将被重定向到 Keycloak 登录页面,成功登录后,他们将被重定向回 localhost:4881,其中呈现编译后的 Angular 应用程序。

当用户登录时,我看到在 Keycloak 中创建了两个会话,一个名为

Regular SSO
,另一个名为
Offline
。根据 SSO 空闲超时,
Regular SSO
会话将被清除。但是,离线会话在 Keycloak 中保留的时间较长,但最终会从 Keycloak 中清除。

在 SSO 会话空闲/SSO 会话最大超时后,我无法将 UI 重定向到 Keycloak 登录页面。我的假设是 Keycloak 应该将此会话超时事件传达给 OAuth2 客户端,并且 OAuth2 客户端应该将 UI 重定向到 Keycloak 登录页面以处理所有后续请求。

如果我在这里遗漏了什么,有人可以告诉我吗?我没有成功找到该问题的相关文档。

我在领域级别设置了

SSO Session Idle
SSO Session Max
Offline Session Settings
。 我也在客户端中设置了
Admin URL

我创建了一个具有完全相同设置的示例应用程序herehttps://github.com/sakethsusarla/keycloak-oauth2-client-ui

backend
:配置为 OAuth2 客户端的 Spring Boot 应用程序,通过
/api/currentTime

公开的 REST API 返回当前时间

frontend
:一个从后端获取当前时间的 Angular 应用程序

realm
:领域配置位于“keycloak-oauth2-client-ui ackend\src\main esources\demo-realm.json"

登录的用户名和密码是

demo
demo

spring-boot spring-security keycloak openid-connect oauth2client
1个回答
1
投票

在了解到 Keycloak 在会话过期时不会启动反向通道注销后,我决定添加一个过滤器来检查令牌的有效性并在需要时使会话无效。

添加以下过滤器对我有用。我已使用

main
branch 中的更改更新了我的存储库。

@Component
public class TokenExpirationFilter extends OncePerRequestFilter {

    private final OAuth2AuthorizedClientRepository oAuth2AuthorizedClientRepository;

    @Autowired
    TokenExpirationFilter(OAuth2AuthorizedClientRepository oAuth2AuthorizedClientRepository) {
        this.oAuth2AuthorizedClientRepository = oAuth2AuthorizedClientRepository;
    }

    @Override
    protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain filterChain) throws ServletException, IOException {
        final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        if (authentication instanceof OAuth2AuthenticationToken token) {
            final OAuth2AuthorizedClient client =
                    oAuth2AuthorizedClientRepository.loadAuthorizedClient(
                            token.getAuthorizedClientRegistrationId(),
                            authentication,
                            request);

            final OAuth2AccessToken accessToken = client.getAccessToken();

            if (accessToken.getExpiresAt() != null && accessToken.getExpiresAt().isBefore(Instant.now())) {
                SecurityContextHolder.getContext().setAuthentication(null);
                SecurityContextHolder.clearContext();

                final HttpSession httpSession = request.getSession();

                if (httpSession != null) {
                    httpSession.invalidate();
                }
            }
        }

        filterChain.doFilter(request, response);
    }
© www.soinside.com 2019 - 2024. All rights reserved.