Home > Blockchain >  Spring Boot post request handler not firing
Spring Boot post request handler not firing

Time:02-17

Thanks for looking into my issue.

I'm practicing with Spring Boot and Spring Security. I've created a simple project with basic registration, but I can't get logging in to work. I'm trying to manually log users in in a POST: /login method, but the method is not firing. When I try to login with POST: /login, it just 302 redirects to GET /login. I'm pretty sure I've set up the security configuration and the method annotations correctly. But the post method isn't even running. (I know because I have a print statement in my post method that's not printing anything even when I start the application and create a user and log in.) How can I fix this?

(I'm not sure if the post method will actually log users in correctly, I just want to get it to run so I can figure that part out.)

The full code is here: https://github.com/Skyler827/SpacePong/tree/7530377a634f1a2fe55ce490402d947616439e72
The Security configurer method:

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();
}

And the Controller which should be working but isn't:

@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:/";
    }
}

CodePudding user response:

I was able to find a workaround solution; I still can't get the custom controller method to execute, but I can log users in, which was my goal.

This project is using Java 17, by the way.

I enabled user login to work by deleting the whole postLogin() method in the controller, and deleting all of the configurations under formLogin() in the configure(HttpSecurity http) method. Once I did this, I no longer had my custom login page, but I did have a default login page, and it did work.

I tried to add the .loginPage("/login") directive back into the configure method to specify the custom login page, but that caused the login form to go back to 302 redirecting to itself, even after my incorrect controller was deleted.

My corrected configure method:

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();
}

My corrected controller:

@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";
    }
}

CodePudding user response:

The Form Login sample has an example of how to configure a custom login page. Some usual issues are not using the correct form action (e.g. action="/login"), incorrectly named form inputs (e.g. name="username", name="password") and missing hidden CSRF input (e.g. type="hidden" name="_csrf" value="...").

The most important detail to remember is that when configuring .formLogin(), Spring Security's filter chain is handling the POST /login request and returning a response prior to your controller, even when .antMatchers("/login").permitAll() is used. This is why you don't see anything hitting your controller method.

While I don't recommend it in most cases, you can play around with handling the POST /login request yourself by simply omitting the .formLogin() part of the DSL. When you do this, you are responsible for setting up the SecurityContext yourself.

  • Related