【问题标题】:Spring Security with OAuth2 losing session带有 OAuth2 的 Spring Security 丢失会话
【发布时间】:2020-08-31 02:33:15
【问题描述】:

我们有一个使用 Spring Security、OAuth2 登录和 Zuul 路由的基于 Spring Boot 的网关。它还使用 Spring Session 在 Redis 中存储会话。此网关在会话中存储 OAuth2 令牌并将 OAuth2 Bearer 令牌转发到后端服务。

我们遇到了用户经常退出登录的问题。看来这大约每小时发生一次。我们甚至不确定是什么导致了所有不同的工具到位。

我们在浏览器中的会话 cookie 的过期时间更长。所以我怀疑是 Spring 使会话无效,或者 OAuth2 令牌过期。

通过快速检查代码,OAuth2TokenRelayFilter 似乎支持刷新令牌。这是正确的吗?

如何找出原因并修复它?

作为参考,我们使用这些版本:

  • Spring Boot 2.1.12
  • Spring Cloud Greenwich.SR4

这里有一些相关的sn-ps。

我们的网页安全配置。

@Configuration
@EnableWebSecurity
@EnableOAuth2Sso
@Order(SecurityProperties.BASIC_AUTH_ORDER - 2)
@Profile("!security-disabled")
public class WebSecurityConfig extends WebSecurityConfigurerAdapter
{
    @Override
    public void configure(HttpSecurity http) throws Exception {
        // @formatter:off
            http
                .authorizeRequests()
                    .antMatchers("/login", "/login/**", "/favicon.ico").permitAll()
                    .antMatchers("/signout").authenticated()
                    .anyRequest().hasAnyRole("ADMIN", "MEMBER")
                    .and()
                .csrf()
                    .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                    .and()
                .httpBasic()
                    .disable()
                .formLogin()
                    .disable()
                .logout()
                    .logoutUrl("/signout")
                    .deleteCookies("SESSION")
                    .and()
            // @formatter:on
    }

API 路径的安全配置。

@Configuration
@Order(SecurityProperties.BASIC_AUTH_ORDER - 2 - 10)
@Profile("!security-disabled")
public class ApiSecurityConfig extends WebSecurityConfigurerAdapter
{
    public void configure(HttpSecurity http) throws Exception {
        // @formatter:off
            http.requestMatchers()
                    .antMatchers("/api/**")
                    .and()
                    .authorizeRequests()
                    .antMatchers("/**").hasAnyRole("ADMIN", "MEMBER")
                        .and()
                    .csrf()
                        .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
                        .and()
                    .headers()
                        .frameOptions().sameOrigin()
                        .and()
                    .httpBasic()
                        .disable()
                    .formLogin()
                        .disable()
                    .logout()
                        .disable()
                    .exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint());
            // @formatter:on
    }

}

更新

我们已经对 Spring 内部进行了一些调试。首先,我们发现我们缺少OAuth2RestTemplate。根据OAuth2 Boot documentation,我们找到了如何添加它:

@Bean
public OAuth2RestTemplate oauth2RestTemplate(
        OAuth2ClientContext oauth2ClientContext,
        OAuth2ProtectedResourceDetails details)
{
    return new OAuth2RestTemplate(details, oauth2ClientContext);
}

这会在OAuth2TokenRelayFilter 调用restTemplate.getAccessToken().getValue(); 时引发异常。

需要重定向才能获得用户的批准

这个异常是从AuthorizationCodeAccessTokenProvider抛出的。

【问题讨论】:

  • 我假设您使用的是旧版 spring-security-oauth2?如果您想使用 Spring Cloud Gateway 以及对 oauth2 客户端的新 Spring 安全支持,sdoxsee.github.io/blog/2019/12/17/…(包括访问令牌的刷新)和spring.io/blog/2019/08/16/… 可能会有所帮助。此外,会话和访问令牌的生命周期应该是独立的。 Webflux Session 生命周期可以这样管理stackoverflow.com/a/62344617/1098564
  • 我们使用的是旧版 spring-security-oauth2。因为我们当前的安全代码不支持 webflux,所以我们还没有转向使用 Spring Cloud Gateway。因此,我们仍然使用 Zuul。

标签: spring spring-boot spring-security spring-security-oauth2


【解决方案1】:

OAuth2TokenRelayFilter

OAuth2TokenRelayFilter 是一个 pre 类型过滤器,它使用 ACCESS_TOKENTOKEN_TYPE 设置上下文,用于进一步的身份验证。它使用getAccessToken() 方法验证令牌,并以“无法获得有效的访问令牌”响应,状态为401。

您可以检查令牌的有效性,并且刷新令牌已正确配置为 grant_typerefresh_token,因为客户端使用刷新令牌授予类型来交换刷新令牌访问令牌过期时的访问令牌,允许客户端继续拥有有效的访问令牌,而无需与用户进一步交互。

如果你想禁用OAuth2TokenRelayFilter,你可以使用下面的

zuul.OAuth2TokenRelayFilter.pre.disable=true

【讨论】:

  • 我们确实想使用 OAuth2TokenRelayFilter(或者我们需要自己编写)。我对原始帖子进行了更新,提供了有关 OAuth2TokenRelayFilter 正在做什么的更多信息。
猜你喜欢
  • 2016-12-05
  • 2011-11-12
  • 2015-07-15
  • 2015-11-23
  • 2018-06-27
  • 2017-12-16
  • 2023-04-06
  • 2015-04-01
  • 2017-10-02
相关资源
最近更新 更多