反应式弹簧云安全(使用 Keycloak):会话到期?

Posted

技术标签:

【中文标题】反应式弹簧云安全(使用 Keycloak):会话到期?【英文标题】:Reactive spring cloud security (with Keycloak): Session expiration? 【发布时间】:2020-10-13 14:45:13 【问题描述】:

我尝试实现以下内容:我想要一个具有一个或多个 Spring Cloud 网关的分布式环境,在这些网关后面是几个(部分)暴露在外部的微服务。对于用户身份验证,我想使用 OIDC(刚刚移至 Keycloak)。

我其实只是坚持使用spring security、webflux和boot的参考文档中的标准配置。

详细来说,我在网关里有:

private final ReactiveClientRegistrationRepository clientRegistrationRepository;

@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) 
    http
            .csrf().disable()
            .authorizeExchange()
            .pathMatchers("/login").permitAll()
            .pathMatchers("/actuator/**").permitAll()
            .anyExchange().authenticated()
            .and()
            .oauth2Login()
            .and()
            .logout(logout -> logout.logoutSuccessHandler(oidcLogoutSuccessHandler()));
    return http.build();


    private ServerLogoutSuccessHandler oidcLogoutSuccessHandler() 
    OidcClientInitiatedServerLogoutSuccessHandler oidcLogoutSuccessHandler =
            new OidcClientInitiatedServerLogoutSuccessHandler(clientRegistrationRepository);

    oidcLogoutSuccessHandler.setPostLogoutRedirectUri(URI.create("https://<host>/login?logout"));

    return oidcLogoutSuccessHandler;

与 application.yml(仅重要部分):

spring:
  cloud:
    gateway:
      default-filters: 
        - TokenRelay=
        - RemoveRequestHeader=Cookie
      discovery:
        locator:
          enabled: true
    consul:
      host: 127.0.0.1
      port: 8500
    loadbalancer:
      ribbon:
        enabled: false
  security:
    oauth2:
      client:
        provider:
          keycloak:
            issuer-uri: $KEYCLOAK_ISSUER_URI
        registration:
          keycloak:
            client-id: $KEYCLOAK_CLIENT_ID
            client-secret: $KEYCLOAK_CLIENT_SECRET
      resourceserver:
        jwt:
          jwk-set-uri: $KEYCLOAK_ISSUER_URI/protocol/openid-connect/certs
server:
  forward-headers-strategy: framework

为了概念证明,我有一个“环境测试应用程序”,控制器只是将声明作为 json 返回。配置如下:

@Bean
public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) 
    http
            .authorizeExchange()
            .pathMatchers("/actuator/**").permitAll()
            .anyExchange().authenticated()
            .and()
            .oauth2ResourceServer()
            .jwt(Customizer.withDefaults());

    return http.build();

application.yml 只包含上面的 consul 和 security 部分。

基本上这是可行的。如果我尝试访问 environment-test-application,我会被重定向到 Keycloak,我必须输入我的凭据并被重定向回 environment-test-application 并查看声明。我可以通过“/logout”退出。

问题:keycloak 会话过期 5 分钟后,我收到 401 并且 chrome 显示“此页面无法正常工作”。即使我一直在重新加载(用户活动),也会发生这种情况。

据我了解,会议应该:

只要有活动就可以扩展(我认为这是刷新令牌的用途,并假设 Spring Security 自动处理此问题) 当用户处于非活动状态一段时间后过期。当用户再次处于活动状态时,他/她应该被重定向到登录,然后返回到原始资源。 点击“记住我”时,应在没有用户活动的情况下重新启动已过期的会话(我认为,这就是 Keycloak 的离线令牌的用途)。

我想这一切都可以通过添加一些简单的配置行来实现,我只是不知道是哪个。参考文档对我来说并不完全清楚,但我觉得默认情况下这一切都是这样处理的。然而,事实并非如此。

注意:我正在使用带有默认 Reactor Netty 的 spring 反应堆栈。因此,既不能使用spring security,也不能使用Keycloak提供的spring boot插件。另外,我不清楚它们如何与标准配置方案交互。

注意:在我用 okta 尝试所有这些之前(使用他们的启动器)。上面描述的问题神奇地似乎与 okta 一起工作。但是,我遇到了不同的问题,因此现在转向开源。

【问题讨论】:

【参考方案1】:

TokenRelayGatewayFilterFactory 添加访问令牌,但在过期时不会刷新它......这就是我相信你得到 401 的原因。有一个开放的 spring 云网关问题,要求提供一个也可以刷新的解决方案。关于该问题的其中一个 cmets 提供了一个实现:https://github.com/spring-cloud/spring-cloud-security/issues/175#issuecomment-557135243。

当刷新令牌过滤器工作时,keycloak 会话仅在您的 spring 云网关“会话”过期后才变得重要,因为如果 keycloak 会话仍然良好,它允许 oauth2 重定向无缝地重新建立会话(即无需再次输入您的凭据)。

如果您希望自定义 webflux 应用程序的会话,有一些解决方案,包括这个:https://***.com/a/62344617/1098564

不确定您的前端使用的是什么,但他是我使用 Spring Security 和 Spring Cloud Gateway 并做出反应的方式:https://sdoxsee.github.io/blog/2019/12/17/merry-microservices-part2-ui-gateway

【讨论】:

酷,我来看看实现。实际上,我正在考虑在我的配置中添加另一个 WebFilter,但仅使用 TokenRelayGatewayFilterFactory 是一个绝妙的主意。我会看看那个并尽快回来。顺便问一下,你知道提醒我功能吗? @PeMa,太好了。抱歉,最近没有使用记住我功能。 @PeMa。我完全不明白你为什么需要使用记住我? 老实说,我并没有真正理解这个想法。但是,据我所见,我只能猜测“记住我”在 Keycloak 中创建了一个离线会话。这可能用于恢复会话,即使在实际刷新令牌过期很久之后。 非常感谢。我刚刚找到时间尝试使用 TokenRelayWithTokenRefreshGatewayFilterFactory。效果很好。

以上是关于反应式弹簧云安全(使用 Keycloak):会话到期?的主要内容,如果未能解决你的问题,请参考以下文章

弹簧反应的弹簧安全会话超时

keycloak CORS 过滤器弹簧靴

使用 keycloak 保护特定的反应页面

如果 keycloak 会话过期,我如何重定向到登录页面?

9大方法为云安全保驾护航

记录以便使用 KeyCloak REST API 创建浏览器会话