我们有一个基于Spring Boot的网关,使用Spring Security、OAuth2登录和Zuul路由。它还使用Spring Session在Redis中存储会话。此网关在会话中存储OAuth2令牌,并将OAuth2承载令牌转发到后端服务。
我们有一个用户经常被注销的问题。似乎这大约每小时发生一次。我们甚至不太确定是什么导致了所有不同的工具到位。
我们在浏览器中的会话cookie会在更长的时间内过期。所以我怀疑要么是Spring使会话无效,要么是OAuth2令牌过期。
通过对代码的快速检查,OAuth2TokenRelayFilter
似乎支持刷新令牌。这是正确的吗?
如何追查原因并解决它?
作为参考,我们使用这些版本:
以下是一些相关片段。
我们的网页安全配置。
@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引导留档,我们发现如何添加它:
@Bean
public OAuth2RestTemplate oauth2RestTemplate(
OAuth2ClientContext oauth2ClientContext,
OAuth2ProtectedResourceDetails details)
{
return new OAuth2RestTemplate(details, oauth2ClientContext);
}
现在,当OAuth2TokenRelayFilter
调用restTemplace. getAccessToken().getValue();
时,这会引发异常。
需要重定向才能获得用户的批准
此异常是从AuthorizationCodeAccessTokenProvider引发的。
OAuth 2令牌中继过滤器
OAuth2TokenRelayFilter
是一个预类型过滤器,它将上下文设置为ACCESS_TOKEN和TOKEN_TYPE,用于进一步的身份验证。它使用getAccessToken()
方法验证令牌,并以401状态响应“无法获得有效的访问令牌”。
您可以检查令牌的有效性并正确配置刷新令牌grant_typerefresh_token当访问令牌过期时,客户端使用刷新令牌授予类型将刷新令牌交换为访问令牌,这允许客户端继续拥有有效的访问令牌,而无需与用户进行进一步交互。
如果您想禁用OAuth2TokenRelayFilter,您可以使用以下方法
zuul.OAuth2TokenRelayFilter.pre.disable=true