Spring Security自定义登录后重定向失效问题求助
问题排查与解决方案
核心原因分析
默认登录页正常但自定义JS登录后跳转失效,本质是会话关联失败——认证成功后,后续请求无法识别已登录的会话,大概率由以下几点导致:
1. CSRF令牌缺失(最常见)
Spring Security默认启用CSRF保护,默认登录页会自动注入CSRF令牌并在提交时携带,但自定义JS请求若未携带该令牌,会导致认证逻辑执行成功,但会话无法被正确绑定到当前用户,后续请求被判定为未认证。
解决方法:
- 在登录页面的HTML头部添加CSRF令牌元标签:
<meta name="_csrf" content="${_csrf.token}"> <meta name="_csrf_header" content="${_csrf.headerName}"> - 在JS的POST请求中携带令牌,同时确保携带会话Cookie:
function login() { const csrfToken = document.querySelector('meta[name="_csrf"]').content; const csrfHeader = document.querySelector('meta[name="_csrf_header"]').content; const username = document.getElementById('username').value; const password = document.getElementById('password').value; fetch('/login', { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded', [csrfHeader]: csrfToken }, body: new URLSearchParams({ username, password }), credentials: 'include' // 必须添加,确保会话Cookie被携带 }) .then(response => { if (response.ok) { window.location.href = '/valide'; // 手动跳转,避免XHR自动跟随重定向的Cookie丢失问题 } }); }
2. 请求格式不匹配
Spring Security默认的UsernamePasswordAuthenticationFilter只处理application/x-www-form-urlencoded格式的请求,若你的JS发送的是JSON格式(application/json),会导致认证逻辑无法解析凭证,看似重定向成功但实际未完成认证。
解决方法:
如果需要支持JSON登录,需在Security配置中添加自定义过滤器:
@Configuration public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .requestMatchers("/login", "/js/**").permitAll() .requestMatchers("/valide").authenticated() ) .formLogin(form -> form .loginProcessingUrl("/login") .defaultSuccessUrl("/valide") .permitAll() ) // 添加JSON认证过滤器 .addFilterBefore(jsonAuthFilter(), UsernamePasswordAuthenticationFilter.class); return http.build(); } @Bean public JsonAuthenticationFilter jsonAuthFilter() throws Exception { JsonAuthenticationFilter filter = new JsonAuthenticationFilter(); filter.setAuthenticationManager(authenticationManagerBean()); filter.setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler("/valide")); return filter; } // 自定义JSON认证过滤器实现示例 static class JsonAuthenticationFilter extends AbstractAuthenticationProcessingFilter { protected JsonAuthenticationFilter() { super(new AntPathRequestMatcher("/login", "POST")); } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException { // 解析JSON格式的用户名密码 LoginRequest loginRequest = new ObjectMapper().readValue(request.getInputStream(), LoginRequest.class); UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken( loginRequest.getUsername(), loginRequest.getPassword() ); return getAuthenticationManager().authenticate(authToken); } } // 辅助DTO类 static class LoginRequest { private String username; private String password; // getter/setter } }
3. 会话Cookie未被携带
若JS请求未配置携带Cookie,即使认证成功,后续跳转请求也无法携带会话ID,导致服务器无法识别已登录用户。
关键检查点:
- 确认JS请求中设置了
credentials: 'include'(同域请求)或credentials: 'same-origin'。 - 检查浏览器Cookie设置,确保允许该站点的Cookie。
- 查看Security配置未禁用Cookie会话跟踪:
http.sessionManagement(session -> session .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED) // 默认配置,不要改为STATELESS );
4. 日志排查验证
查看Spring Security的DEBUG日志,重点关注以下内容:
- 搜索
UsernamePasswordAuthenticationFilter,确认是否输出Authentication success日志,以及认证后的用户信息。 - 搜索
SecurityContextPersistenceFilter,确认SecurityContext是否被正确保存到会话中(日志包含SecurityContext stored to HttpSession)。 - 搜索
CsrfFilter,若出现Invalid CSRF token found for,说明CSRF令牌未正确携带。
内容的提问来源于stack exchange,提问作者Bhorah
相关产品推荐
相关产品推荐

