Search code examples
javaspringspring-bootspring-securityspring-session

Implementing login manually with Spring Security


I am developing an application with Spring Boot. I now want to implement account control, and I'm introducing Spring Session and Spring Security. This is a back-end application based on REST services, the front-end will be a separate application consuming those services. I want to control that every user accessing the resources is logged in.

I don't want Spring Security to handle the login automatically, I want to implement my custom login service, in my already existing CustomerController, which is controlling other services.

My Controller:

@RestController
@RequestMapping("/customer")
public class CustomerController {

    @Autowired
    private AuthenticationService authenticationService;

    @PostMapping("/login")
    public ResponseEntity loginSubmit(@RequestBody LoginForm form) {
        Errors errors = authenticationService.validateLoginForm(form);
        if (!errors.hasErrors()) {
            CustomerDTO result = authenticationService.findCustomerByEmailAndPassword(form);
            return new ResponseEntity(result, HttpStatus.OK);
        } else {
            return new ResponseEntity(errors.getAllErrors(), HttpStatus.OK);
        }
    }

    @GetMapping("/login")
    public ResponseEntity testBrowser() {
        return new ResponseEntity("Hello world", HttpStatus.OK);
    }

    [ . . . Other services . . . ]
}

Spring Security configuration:

@EnableWebSecurity
@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                    .anyRequest().authenticated()
                    .and()
                .formLogin()
                    .loginPage("/customer/login")
                    .permitAll()
                    .and()
                .logout()
                    .permitAll()
                    .and()
                .httpBasic();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/h2-console/**");
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}

Effectively, this restricts all unlogged users from accessing any service, except login. In my controller, I've got two login methods implemented. One is a GET for testing purposes, the other one is a POST. When I access with the browser (GET) it works and I can hit the breakpoint. However when I try the POST (via Postman) it returns 401 Unauthorised, like the rest of the services that require login. The breakpoint never gets hit.

I believe I'm following the pattern. What am I missing please?


Solution

  • There are two parameters mentioned in spring security docs:

    1. login-page
    2. login-processing-url

    First one is where user will be redirected using GET in case if not logged, and the second one is where login page's form is submitted using POST.

    You are receiving 401 Unauthorised because the default value for login-processing-url is /login and not /customer/login

    docs: https://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/