You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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页面。

问题原因及解决方案

核心原因

  1. /login的GET请求未放行:安全配置中仅通过formLogin().loginPage("/login").permitAll()放行登录相关的POST请求,但访问/login页面本身是GET请求,未被明确放行,导致未认证用户访问时陷入重定向循环。
  2. 根路径/未配置放行:anyRequest().authenticated()要求所有请求都需要认证,根路径/自然会被拦截重定向。
  3. 静态资源未放行:Spring Security默认拦截所有静态资源请求(如/favicon.ico),需单独配置放行。
  4. Bean重复声明冲突:通过构造注入了UserDetailsService和PasswordEncoder后,又重复声明同名Bean,可能导致Spring注入混乱,引发认证逻辑异常。
  5. 控制器注解不匹配: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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.06 16:43:20