【问题标题】:Spring Cloud Gateway deletes SESSION cookie after a call to resource serverSpring Cloud Gateway 在调用资源服务器后删除 SESSION cookie
【发布时间】:2019-12-23 16:16:00
【问题描述】:

在调用资源服务器后,Spring Cloud Gateway 重置 SESSION cookie 时遇到问题。

我有一个 Angular 应用程序、一个 Spring Cloud Gateway 应用程序、一个外部授权服务器和一个我自己的资源服务器。

Angular 应用程序首先通过 Spring Cloud Gateway 应用程序进行授权(该应用程序使用 OAuth2 将这项工作委托给外部授权服务器)并接收SESSION cookie。此时用户已通过身份验证,Authentication 对象在 Spring Cloud Gateway 应用程序中可用。

接下来,Angular 应用程序调用 Spring Cloud Gateway 应用程序的端点,该端点实际上将调用转发到资源服务器(并在调用中包含 Bearer 令牌,因此调用正常),资源服务器返回一些结果,它通过 Spring Cloud Gateway 应用程序成功发送回 Angular 应用程序。但是除了成功响应之外,Spring Cloud Gateway 应用程序还会发送此标头:

set-cookie: SESSION=; Max-Age=0; Expires=Sat, 17 Aug 2019 20:39:44 GMT; Path=/; HTTPOnly

即使Authentication 对象仍然存在并且会话看起来也很好,这会杀死客户端的 cookie 并使后续调用变得不可能。

有谁知道这种行为的原因是什么?

【问题讨论】:

  • 网关根本不创建cookie,其他的是:下游应用程序或spring security或其他,但它不是网关。
  • @spencergibb 对不起,我可能不够清楚。我想说的是使用 Spring Cloud Gateway 将调用从 Angular 应用程序转发到资源服务器的应用程序正在使用 Spring Reactive Security 和 OAuth2 与外部身份验证服务器,但由于某种原因,一旦请求被转发到任何资源,cookie 就会失效服务器。我已经通过实现删除标头的GlobalFilter 来解决它,但想知道 cookie 被删除的原因是什么,或者至少得到一个线索 what 可能正在设置标头跨度>
  • 在遇到同样的问题后,我发现在ServerHttpSecurity 中禁用requestCache 解决了这个问题,并且网关不再删除SESSION cookie。我真的不知道为什么。
  • 如何禁用 requestCache? http.requestCache.disable() 无效。
  • @horatius 请看我提供的答案:stackoverflow.com/a/66444832/2578324

标签: session cookies session-cookies spring-cloud spring-cloud-gateway


【解决方案1】:

我也遇到过同样的情况。

外部授权服务器是否生成了 base64 编码的 cookie? 如Set-Cookie: SESSION=YWZjOTc4YmUtOTNmNy00N2UxLTg0NjgtYWJlNWMwZmNiOWUx

如果是这样,就会导致问题。

Spring Cloud Gateway 使用的 Spring Web 中定义的 CookieWebSessionIdResolver 不处理 base64 编码的 cookie 值。相反,它直接使用原始 cookie 值在存储中查找相应的会话。显然,不会找到任何 Authentication 对象。因此 Spring Cloud Gateway 选择终止 Angular 应用程序提供的“无效”cookie。

下面给出了两种解决方案。

  1. 如果外部授权服务器也由您管理,请禁用 cookie 值的 base64 编码。

  2. 重写 WebSessionIdResolver 以更改默认行为,以便在会话管理器读取时解码 cookie 值。并且不要忘记在 Spring Cloud Gateway 实现中将其注册为 Spring Bean。

就我而言,选择了解决方案 1。我的授权服务器使用 Spring Security + Spring Session。我像这样更改了HttpSessionIdResolver 的默认设置。

    CookieHttpSessionIdResolver cookieHttpSessionIdResolver = new CookieHttpSessionIdResolver();
    DefaultCookieSerializer defaultCookieSerializer = new DefaultCookieSerializer();
    defaultCookieSerializer.setUseBase64Encoding(false);
    defaultCookieSerializer.setCookieName("SESSION");
    cookieHttpSessionIdResolver.setCookieSerializer(defaultCookieSerializer);

【讨论】:

  • 这个答案对我有用。先前基于禁用请求缓存的答案仅在一段时间内有效,但不是稳定的解决方案。我按照您建议的 int 选项 1 禁用了 base64 会话 cookie 编码。我没有找到读取 WebSessionIdResolver 中的 cookie 值来解码 base64 值的方法。
【解决方案2】:

我们的 WebFlux 资源服务器中存在 exact 问题 - API 网关会将请求代理到资源服务器,因此第一个请求有效,但后续请求由于SESSION cookie 被清除,将尝试再次进行身份验证,从而导致一些X-XSRF-TOKEN 错误。

我们通过在 WebFlux 资源服务器中将 .requestCache().requestCache(NoOpServerRequestCache.getInstance()) 添加到 securityWebFilterChain bean 定义来解决此问题。

@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
class ResourceServerConfiguration {

    @Value('${spring.security.oauth2.resourceserver.jwt.jwk-set-uri}')
    String jwkSetUri

    @Bean
    SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {
        http
                .csrf().disable()     
                .requestCache().requestCache(NoOpServerRequestCache.getInstance()).and()
                .httpBasic().disable()
                .formLogin().disable()
                .oauth2ResourceServer().jwt().jwkSetUri(jwkSetUri)
                .and().and()
                .authorizeExchange()
                .pathMatchers("/v1/**").authenticated()                
    }
}

在“经典”MVC 世界中,您可以像这样配置ResourceServerConfigurer 类:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.sessionManagement()
    .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}

【讨论】:

  • 这实际上帮助了我。我在将索赔从 JWT 中取出时遇到了问题。它基本上是在擦除数据。一旦我添加了这一行,问题就消失了。
猜你喜欢
  • 2020-08-14
  • 2021-04-03
  • 2021-12-08
  • 2021-10-23
  • 2018-07-19
  • 2015-04-27
  • 2020-11-04
  • 2017-09-23
  • 2019-09-16
相关资源
最近更新 更多