Spring Security遇登录重定向循环,如何获取登录表单?
问题解决:重定向循环与登录表单配置
一、解决重定向循环问题
你的请求出现重定向循环,核心原因有两个:
- CSRF保护拦截POST请求:Spring Security默认开启CSRF保护,对于POST请求,若未携带CSRF Token,会被拦截并重定向到登录页,而无状态会话(
STATELESS)的配置导致循环重定向。 - Form Login配置与RESTful认证冲突:同时配置JWT无状态认证和传统表单登录,两种认证规则相互干扰,导致REST接口请求被错误拦截。
修改SecurityConfig代码如下:
@Configuration @EnableWebSecurity @RequiredArgsConstructor public class SecurityConfig { private final JwtAuthenticationFilter jwtAuthFilter; private final AuthenticationProvider authenticationProvider; @Bean public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception { httpSecurity // 禁用CSRF:RESTful API无状态,无需CSRF保护 .csrf(csrf -> csrf.disable()) .authorizeRequests(authorize -> authorize .requestMatchers("/api/v3/auth/**").permitAll() .anyRequest().authenticated() ) .sessionManagement(session -> session .sessionCreationPolicy(SessionCreationPolicy.STATELESS) ) .authenticationProvider(authenticationProvider) .addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class); return httpSecurity.build(); } }
若确实需要保留传统表单登录功能,需添加视图控制器处理/login请求,同时调整formLogin配置避免干扰REST接口:
// 在SecurityConfig中添加视图控制器配置 @Bean public WebMvcConfigurer webMvcConfigurer() { return new WebMvcConfigurer() { @Override public void addViewControllers(ViewControllerRegistry registry) { registry.addViewController("/login").setViewName("login"); } }; } // 在securityFilterChain中调整formLogin配置 .formLogin(formLogin -> formLogin .loginPage("/login") .loginProcessingUrl("/api/v3/auth/login") // 指定表单提交的处理路径 .permitAll() .defaultSuccessUrl("/") )
二、获取登录表单的方式
根据应用架构选择对应方案:
1. 服务器端渲染表单
创建@Controller处理/login请求,返回HTML登录页面:
@Controller public class LoginController { @GetMapping("/login") public String showLoginForm() { // 返回登录页面视图名称,需确保模板引擎(如Thymeleaf)存在对应的login.html文件 return "login"; } }
2. 前后端分离架构(前端自行构建表单)
前端自行构建登录表单,通过POST请求调用/api/v3/auth/authenticate接口,传递包含用户名和密码的JSON数据,获取JWT Token后,后续请求在请求头中携带Authorization: Bearer {token}完成认证。
示例前端请求(JavaScript):
fetch('/api/v3/auth/authenticate', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ username: 'your-username', password: 'your-password' }) }) .then(response => response.json()) .then(data => { localStorage.setItem('token', data.token); });
内容的提问来源于stack exchange,提问作者Elijah Sokol
相关产品推荐
相关产品推荐

