Spring Authorization Server v1.1.3中Remember Me的autoLogin未触发问题排查
基于Spring Authorization Server(v1.1.3)实现多Web应用SSO功能,同时为身份提供商添加用户管理及全局管理REST接口,客户端均为Spring Cloud Gateway BFF架构的React SPA。参考官方示例项目后功能正常,但启用Remember Me时autoLogin方法始终未触发,每次都跳转到表单登录页。首次登录后remember me token已正确持久化,后续请求也携带对应cookie。
安全配置代码如下:
@Configuration @EnableMethodSecurity public class SecurityConfig { @Bean @Order(1) public SecurityFilterChain authorizationServerSecurityFilterChain(HttpSecurity http) throws Exception { OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http); http.getConfigurer(OAuth2AuthorizationServerConfigurer.class) .oidc(Customizer.withDefaults()); http .exceptionHandling(exception -> exception .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/login"))) .cors(Customizer.withDefaults()) .csrf(CsrfConfigurer::disable); return http.build(); } @Bean @Order(2) public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http, RememberMeServices rememberMeServices) throws Exception { http .authorizeHttpRequests(authorize -> authorize .anyRequest().authenticated()) .oauth2ResourceServer(resourceServer -> resourceServer.jwt(Customizer.withDefaults())) .formLogin(Customizer.withDefaults()) .rememberMe(remember -> remember.rememberMeServices(rememberMeServices)) .cors(Customizer.withDefaults()) .csrf(CsrfConfigurer::disable); return http.build(); } @Bean public RememberMeServices rememberMeServices(UserDetailsService userDetailsService, PersistentTokenRepository persistentTokenRepository) { return new PersistentTokenBasedRememberMeServices("superSecretKey", userDetailsService, persistentTokenRepository); } ... }
RememberMeAuthenticationFilter已存在于SecurityFilterChain中,但根据FilterOrderRegistration的设计,它位于DefaultLoginPageGeneratingFilter之后,而Spring Security官方文档指出它应该紧跟在UsernamePasswordAuthenticationFilter之后。
问题核心是RememberMeAuthenticationFilter的顺序错误,导致在触发自动登录逻辑前,请求已被引导至登录页面。以下是两种可行的修复方案:
方案1:手动调整过滤器顺序
在defaultSecurityFilterChain中,通过addFilterAfter手动将RememberMeAuthenticationFilter放置在UsernamePasswordAuthenticationFilter之后,覆盖默认顺序:
@Bean @Order(2) public SecurityFilterChain defaultSecurityFilterChain(HttpSecurity http, RememberMeServices rememberMeServices) throws Exception { // 获取Spring Security自动配置的UsernamePasswordAuthenticationFilter UsernamePasswordAuthenticationFilter usernamePasswordFilter = http.getSharedObject(UsernamePasswordAuthenticationFilter.class); http .authorizeHttpRequests(authorize -> authorize .anyRequest().authenticated()) .oauth2ResourceServer(resourceServer -> resourceServer.jwt(Customizer.withDefaults())) .formLogin(Customizer.withDefaults()) .rememberMe(remember -> remember.rememberMeServices(rememberMeServices)) // 手动指定过滤器顺序,确保紧跟在用户名密码认证过滤器之后 .addFilterAfter(new RememberMeAuthenticationFilter( http.getSharedObject(AuthenticationManager.class), rememberMeServices ), UsernamePasswordAuthenticationFilter.class) .cors(Customizer.withDefaults()) .csrf(CsrfConfigurer::disable); return http.build(); }
方案2:全局调整过滤器默认顺序
通过自定义FilterOrderRegistration Bean,修改Spring Security的默认过滤器顺序规则,确保RememberMeAuthenticationFilter始终在UsernamePasswordAuthenticationFilter之后执行:
@Configuration public class FilterOrderConfig { @Bean public FilterOrderRegistration filterOrderRegistration() { FilterOrderRegistration registration = new FilterOrderRegistration(); // 将RememberMe过滤器的顺序设置为用户名密码过滤器顺序+1 registration.put(RememberMeAuthenticationFilter.class, FilterOrderRegistration.getOrder(UsernamePasswordAuthenticationFilter.class) + 1); return registration; } }
额外验证项
- 确认
PersistentTokenRepository的实现(如JDBC/JPA)配置正确,token能正常写入和读取数据库。 - 生产环境中替换硬编码的
superSecretKey为安全的随机密钥,可通过配置文件注入。 - 检查请求中的remember me cookie名称是否与
PersistentTokenBasedRememberMeServices默认的remember-me一致,若自定义名称需在rememberMeServices中显式设置。
内容的提问来源于stack exchange,提问作者vgabor

