Spring 启动 post 请求处理程序未触发

Spring Boot post request handler not firing

感谢您调查我的问题。

我正在练习 Spring 启动和 Spring 安全。我已经通过基本注册创建了一个简单的项目,但我无法登录工作。我正在尝试使用 POST: /login 方法手动登录用户,但该方法未触发。当我尝试使用 POST: /login 登录时,它只是 302 重定向到 GET /login。我很确定我已经正确设置了安全配置和方法注释。但是 post 方法甚至不是 运行ning。 (我知道,因为我的 post 方法中有一个打印语句,即使在我启动应用程序并创建用户并登录时也不会打印任何内容。)我该如何解决这个问题?

(我不确定 post 方法是否真的能让用户正确登录,我只是想把它变成 运行 这样我就可以弄清楚那部分了。)

完整代码在这里:https://github.com/Skyler827/SpacePong/tree/7530377a634f1a2fe55ce490402d947616439e72
安全配置器方法:

protected void configure (HttpSecurity http) throws Exception {
    http
        .csrf()
            .ignoringAntMatchers("/h2/**")
            .and()
        .headers()
            .frameOptions().sameOrigin().and()
        .authorizeRequests()
            .antMatchers("/login", "/register", "/h2/**").permitAll()
            .antMatchers(HttpMethod.POST, "/login").permitAll()
            .anyRequest().authenticated()
            .and()
        .formLogin()
            .loginProcessingUrl("/login")
            .loginPage("/login")
            .failureUrl("/login?error=true")
            .successForwardUrl("/")
            .and()
        .logout()
            .logoutUrl("/logout")
            .logoutSuccessUrl("/")
            .permitAll();
}

应该工作但没有工作的控制器:

@Controller
@RequestMapping("/login")
public class LoginController {
    private final AuthenticationManager authManager;
    private final PlayerService playerService;
    public LoginController(AuthenticationManager authManager, PlayerService playerService) {
        this.authManager = authManager;
        this.playerService = playerService;
    }
    @GetMapping
    public String getLogin(Model model) {
        model.addAttribute("playerdto", new PlayerDto());
        System.out.println("running getLogin()");
        return "login";
    }
    @PostMapping
    public String postLogin(@ModelAttribute("playerdto") PlayerDto playerDto, Model model) {
        System.out.println("running postLogin()");
        Player player = playerService.getPlayerByName(playerDto.getUsername());
        if (player == null) {
            model.addAttribute("error", "invalid login");
            return "login";
        }

        UsernamePasswordAuthenticationToken authReq = new UsernamePasswordAuthenticationToken(
                playerDto.getUsername(), playerDto.getPassword());
        Authentication auth = authManager.authenticate(authReq);

        return "redirect:/";
    }
}

我找到了解决方法;我仍然无法执行自定义控制器方法,但我可以让用户登录,这是我的目标。

这个项目用的是Java17,顺便说一下。

我通过删除控制器中的整个postLogin()方法并删除configure(HttpSecurity http)方法中formLogin()下的所有配置来启用用户登录。一旦我这样做了,我就不再有我的自定义登录页面,但我有一个默认登录页面,而且它确实有效。

我试图将 .loginPage("/login") 指令重新添加到配置方法中以指定自定义登录页面,但这导致登录表单返回到 302 重定向到自身,即使在我不正确的控制器被删除之后.

我更正的配置方法:

protected void configure (HttpSecurity http) throws Exception {
    http
        .csrf()
            .ignoringAntMatchers("/h2/**")
            .and()
        .headers()
            .frameOptions().sameOrigin().and()
        .authorizeRequests()
            .antMatchers("/login", "/register", "/h2/**").permitAll()
            .anyRequest().authenticated()
            .and()
        .formLogin()
        .and()
        .logout()
            .logoutUrl("/logout")
            .logoutSuccessUrl("/")
            .permitAll();
}

我更正的控制器:

@Controller
@RequestMapping("/login")
public class LoginController {
    private final AuthenticationManager authManager;
    private final PlayerService playerService;
    public LoginController(AuthenticationManager authManager, PlayerService playerService) {
        this.authManager = authManager;
        this.playerService = playerService;
    }
    @GetMapping
    public String getLogin(Model model) {
        model.addAttribute("playerdto", new PlayerDto());
        System.out.println("running getLogin()");
        return "login";
    }
}

Form Login 示例中有一个如何配置自定义登录页面的示例。一些常见问题是未使用正确的表单操作(例如 action="/login")、错误命名的表单输入(例如 name="username"name="password")和缺少隐藏的 CSRF 输入(例如 type="hidden" name="_csrf" value="...") .

要记住的最重要的细节是,在配置 .formLogin() 时,Spring 安全的过滤器链正在处理 POST /login 请求并在您的控制器之前返回响应,即使 .antMatchers("/login").permitAll() 被使用。这就是为什么您看不到任何影响您的控制器方法的原因。

虽然在大多数情况下我不推荐它,但您可以通过简单地省略 DSL 的 .formLogin() 部分来尝试自己处理 POST /login 请求。执行此操作时,您有责任自行设置 SecurityContext