我在调用资源服务器后SESSION
Spring Cloud Gateway 重置 cookie 时遇到问题。
我有一个 Angular 应用程序、一个 Spring Cloud Gateway 应用程序、一个外部授权服务器和一个我自己的资源服务器。
Angular 应用程序首先通过 Spring Cloud Gateway 应用程序(使用 OAuth2 将此工作委托给外部授权服务器(进行授权,并接收SESSION
cookie。此时,用户已通过身份验证Authentication
并且该对象在Spring Cloud Gateway应用程序中可用。
接下来,Angular 应用程序调用 Spring Cloud Gateway应用程序的端点,该终结点实际上将调用转发到资源服务器(并在调用中包含持有者令牌,因此调用工作正常(,资源服务器返回一些结果,该结果通过 Spring Cloud Gateway 应用程序成功发送回 Angular 应用程序。 但是,除了成功的响应外,Spring Cloud Gateway 应用程序还会发送以下标头:
set-cookie: SESSION=; Max-Age=0; Expires=Sat, 17 Aug 2019 20:39:44 GMT; Path=/; HTTPOnly
这会杀死客户端的 cookie 并使后续调用变得不可能,即使Authentication
对象仍然处于活动状态并且会话看起来也很好。
有谁知道这种行为的原因是什么?
我们在 WebFlux 资源服务器中遇到了确切的问题——API 网关会将请求代理到资源服务器,因此第一个请求有效,但后续请求将尝试再次进行身份验证,因为SESSION
cookie 被清除,导致一些X-XSRF-TOKEN
错误。
我们通过在 WebFlux 资源服务器中的securityWebFilterChain
Bean 定义中添加.requestCache().requestCache(NoOpServerRequestCache.getInstance())
来解决此问题。
@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);
}
更新 11/22/2022
我们的微服务架构已经开始扩展,我们开始在不属于我们团队的服务上再次看到这个问题。事实证明,它们具有有状态的Web服务,这意味着在调用它们时会创建会话,这导致SESSION cookie在Spring Cloud Gateway客户端应用程序上被覆盖。我们将此应用于我们的配置以永久解决此问题:
server:
reactive:
session:
cookie:
name: SESSION_${spring.application.name}
👆 这消除了来自其他 Web 服务调用的SESSION
Cookie 与网关客户端的SESSION
Cookie 冲突的问题。
我遇到了同样的情况。
外部授权服务器是否生成了 base64 编码的 cookie? 如Set-Cookie: SESSION=YWZjOTc4YmUtOTNmNy00N2UxLTg0NjgtYWJlNWMwZmNiOWUx
如果是这样,则会导致问题。
SpringCloud Gateway 使用的 Spring Web 中定义的 CookieWebSessionIdResolver 不处理 base64 编码的 cookie 值。相反,它直接使用原始 cookie 值在存储中查找相应的会话。显然,不会找到身份验证对象。因此,Spring Cloud Gateway选择杀死Angular应用程序给出的"无效"cookie。
下面给出了两种解决方案。
在外部授权服务器中禁用 Cookie 值的 base64 编码(如果它也由您管理(。
覆盖 WebSessionIdResolver 以更改默认行为,以便在会话管理器读取时解码 cookie 值。并且不要忘记在Spring Cloud Gateway实现中将其注册为Spring Bean。
就我而言,选择了解决方案1。我的授权服务器使用 Spring 安全性 + Spring 会话。我像这样更改了HttpSessionIdResolver
的默认设置。
CookieHttpSessionIdResolver cookieHttpSessionIdResolver = new CookieHttpSessionIdResolver();
DefaultCookieSerializer defaultCookieSerializer = new DefaultCookieSerializer();
defaultCookieSerializer.setUseBase64Encoding(false);
defaultCookieSerializer.setCookieName("SESSION");
cookieHttpSessionIdResolver.setCookieSerializer(defaultCookieSerializer);