Spring Boot访问/或/register时总是重定向到/login问题求助
Spring Boot 重定向问题排查
问题现象
应用默认页面为http://localhost:8080/login,但访问http://localhost:8080/或http://localhost:8080/register时,总是被重定向到/login。
已尝试的安全配置
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { private final UserDetailsService userDetailsService; private final PasswordEncoder passwordEncoder; public SecurityConfig(UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) { this.userDetailsService = userDetailsService; this.passwordEncoder = passwordEncoder; } @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/register").permitAll() .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") .permitAll() .and() .logout() .permitAll(); } @Bean public UserDetailsService userDetailsService() { return userDetailsService; } @Bean public PasswordEncoder passwordEncoder() { return passwordEncoder; } }
控制器代码
package Login; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.http.ResponseEntity; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.web.bind.annotation.*; @RestController public class LoginController { private final LoginRepository loginRepository; private final PasswordEncoder passwordEncoder; private static final Logger logger = LoggerFactory.getLogger(LoginController.class); public LoginController(LoginRepository loginRepository, PasswordEncoder passwordEncoder) { this.loginRepository = loginRepository; this.passwordEncoder = passwordEncoder; } @PostMapping("/register") public ResponseEntity<String> registerUser(@RequestBody UserLogin user){ logger.debug("Received registration request for user: {}", user.getUsername()); UserLogin existingUser = loginRepository.findByUsername(user.getUsername()); if(existingUser != null){ return ResponseEntity.badRequest().body("Benutzername existiert bereits!"); } else{ String encryptedPW = passwordEncoder.encode(user.getPassword()); user.setPassword(encryptedPW); loginRepository.save(user); return ResponseEntity.ok("Benutzer wurde erfolgreich erstellt!"); } } @PostMapping("/login") public ResponseEntity<String> newLogin(@RequestParam String username, @RequestParam String password) { UserLogin user = loginRepository.findByUsername(username); if (user != null && passwordEncoder.matches(password, user.getPassword())) { return ResponseEntity.ok("Du bist eingeloggt!"); } else { return ResponseEntity.badRequest().body("Ungültige Anmeldeinformationen"); } } }
日志信息
访问
/register和/login时,授权尝试失败,FilterSecurityInterceptor报告请求来自未认证用户,随后LoginUrlAuthenticationEntryPoint执行,将请求重定向到/login页面。
访问/favicon.ico时,同样出现授权失败,被重定向回/login页面。
问题原因及解决方案
核心原因
/login的GET请求未放行:安全配置中仅通过formLogin().loginPage("/login").permitAll()放行登录相关的POST请求,但访问/login页面本身是GET请求,未被明确放行,导致未认证用户访问时陷入重定向循环。- 根路径
/未配置放行:anyRequest().authenticated()要求所有请求都需要认证,根路径/自然会被拦截重定向。 - 静态资源未放行:Spring Security默认拦截所有静态资源请求(如
/favicon.ico),需单独配置放行。 - Bean重复声明冲突:通过构造注入了
UserDetailsService和PasswordEncoder后,又重复声明同名Bean,可能导致Spring注入混乱,引发认证逻辑异常。 - 控制器注解不匹配:
LoginController使用@RestController会让所有方法返回JSON,但Thymeleaf页面需要@Controller返回视图,两者混用会导致页面跳转逻辑失效。
修正后的安全配置
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { private final UserDetailsService userDetailsService; private final PasswordEncoder passwordEncoder; public SecurityConfig(UserDetailsService userDetailsService, PasswordEncoder passwordEncoder) { this.userDetailsService = userDetailsService; this.passwordEncoder = passwordEncoder; } @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() // 放行注册、登录页面/接口、根路径及静态资源 .antMatchers("/register", "/login", "/", "/favicon.ico").permitAll() // 其他所有请求需要认证 .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") .permitAll() .and() .logout() .permitAll(); } @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 绑定自定义用户服务和密码编码器 auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder); } // 移除重复的Bean声明,避免注入冲突 }
控制器调整建议
拆分控制器,分别处理视图跳转和API接口:
// 处理页面跳转的控制器 @Controller public class PageController { @GetMapping("/login") public String loginPage() { return "login"; // 返回Thymeleaf视图名称 } @GetMapping("/register") public String registerPage() { return "register"; // 返回Thymeleaf视图名称 } } // 处理接口请求的控制器 @RestController @RequestMapping("/api") public class AuthApiController { private final LoginRepository loginRepository; private final PasswordEncoder passwordEncoder; public AuthApiController(LoginRepository loginRepository, PasswordEncoder passwordEncoder) { this.loginRepository = loginRepository; this.passwordEncoder = passwordEncoder; } @PostMapping("/register") public ResponseEntity<String> registerUser(@RequestBody UserLogin user){ // 原注册逻辑 } // 注:Spring Security的formLogin会自动处理/login的POST提交,无需自定义该接口,避免冲突 }
内容的提问来源于stack exchange,提问作者Marco
相关产品推荐
相关产品推荐

