Testing login api Spring Security with Postman

4k Views Asked by At

I am Working on a spring boot project for an e-commerce website, As a beginner, I try to add spring security in it so the problem is when I try to test my rest login API using postman I have a status code 200 and the body is always the default login page of spring security. I will be thankful for any advice or any solution.

Here is my user class :

    public class User implements Serializable {

    private static final long serialVersionUID = -2800960695811489984L;
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private long id;
    private String firstName;
    private String lastName;
    @Column(nullable = false, unique = true)
    private String username;
    @Column(nullable = false)
    private String address;
    @Column(nullable = false, unique = true)
    private String email;
    private String password;
    private boolean isEnabled;

    @Column(name = "role" , nullable = false)
    @Enumerated(EnumType.STRING)
    private Role role;

Here is my Role enum :

    public enum Role {
    USER ,ADMIN
}

MyUserDetails Class :

public class MyUserDetails implements UserDetails {
    String ROLE_PREFIX ="ROLE_";

    private String email;
    private String password;
    private boolean active;
    private Role role;

    public MyUserDetails(User user) {
        super();
        this.email = user.getEmail();
        this.password = user.getPassword();
        this.active = user.isEnabled();
        this.role = role;
    }

    public MyUserDetails(String email, String password, boolean enabled, Role role) {
        super();
    }

    public static MyUserDetails create(User user) {

        return new MyUserDetails(user.getEmail(), user.getPassword() ,user.isEnabled(), user.getRole());

    }

Here is MyUserDetailsService :

@Service
@ToString
public class MyUserDetailsService implements UserDetailsService {
    UserRepository userRepository;

    @Autowired
    public MyUserDetailsService(UserRepository userRepository) {
        super();
        this.userRepository = userRepository;
    }

    @Override
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
        if (email == null || email.isEmpty()) {
            throw new UsernameNotFoundException("email is Empty");
        }

        User user = userRepository.findByEmail(email);
        if (user != null) {
            return user.toCurrentUserDetails();
        }
        throw new UsernameNotFoundException( email + "is not found !!!");
    }
}

Here is my RestController :

@CrossOrigin(origins = "*")
@RestController
@RequestMapping("/home")
public class HomeController {

    private AuthenticationManager authenticationManager;
    private MyUserDetailsService userDetailsService;
    private UserRepository userRepository;
    private Jwt jwtUtil;


    @Autowired
    public HomeController(AuthenticationManager authenticationManager, MyUserDetailsService userDetailsService
            , UserRepository userRepository, Jwt jwtUtil) {
        this.authenticationManager = authenticationManager;
        this.userDetailsService = userDetailsService;
        this.userRepository = userRepository;
        this.jwtUtil = jwtUtil;
    }

    @PostMapping("/signin")
    public ResponseEntity<ServerResp> addUser(@RequestBody User user) {

        ServerResp response = new ServerResp();
        try {
            if (Validator.isUserEmpty(user)) {
                response.setStatus(ResponseCode.BAD_REQUEST_CODE);
                response.setMessage(ResponseCode.BAD_REQUEST_MESSAGE);
            } else if (!Validator.isValidEmail(user.getEmail())) {
                response.setStatus(ResponseCode.BAD_REQUEST_CODE);
                response.setMessage(ResponseCode.INVALID_EMAIL_FAIL_MSG);

            } else {
                user.setRole(Role.USER);
                user.setEnabled(true);
                User reg = userRepository.save(user);
                response.setStatus(ResponseCode.SUCCESS_CODE);
                response.setMessage(ResponseCode.CUST_REG);


            }
        } catch (Exception e) {
            response.setStatus(ResponseCode.FAILURE_CODE);
            response.setMessage(e.getMessage());
        }
        return new ResponseEntity<ServerResp>(response, HttpStatus.ACCEPTED);
    }


    @PostMapping("/login")
    public ResponseEntity<ServerResp> authentification(@RequestBody HashMap<String, String> credential) {

        final String email = credential.get(WebConstants.USER_EMAIL);
        final String password = credential.get(WebConstants.USER_PASSWORD);
        try {
            authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(email, password));
        } catch (BadCredentialsException e) {
            throw new UserNotFoundException(email);

        }
        final UserDetails userDetails = userDetailsService.loadUserByUsername(email);
        final String jwt = jwtUtil.generateToken(userDetails);

        ServerResp resp = new ServerResp();
        resp.setStatus(ResponseCode.SUCCESS_CODE);
        resp.setMessage(ResponseCode.SUCCESS_MESSAGE);
        resp.setAUTH_TOKEN(jwt);

        return new ResponseEntity<ServerResp>(resp, HttpStatus.OK);

    }



}

Here is my Security Configuration Class :

@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    private MyUserDetailsService userDetailsService;
    private JwtFilter jwtFilter;
    @Autowired
    DataSource datasource;


    @Autowired
    public SecurityConfiguration(MyUserDetailsService userDetailsService, JwtFilter jwtFilter) {
        this.userDetailsService = userDetailsService;
        this.jwtFilter = jwtFilter;
    }

    public SecurityConfiguration(boolean disableDefaults, MyUserDetailsService userDetailsService, JwtFilter jwtFilter) {
        super(disableDefaults);
        this.userDetailsService = userDetailsService;
        this.jwtFilter = jwtFilter;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
       http.csrf().disable().authorizeRequests().antMatchers("/resources/**", "/static/**", "/public/**").permitAll()
                .antMatchers("/home/**").permitAll()
                .antMatchers("/admin/**").hasRole("ADMIN")
                .antMatchers("/user/**")
                .hasRole("USER")
                .anyRequest().authenticated().and().sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);

       http
                .formLogin()
                //.loginPage("/home/login")
                .usernameParameter("email")
                .passwordParameter("password")
                .permitAll()

                .and()
                .logout()
                .permitAll();

        http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);



    }



    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        // TODO Auto-generated method stub
        return super.authenticationManagerBean();
    }

    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

}

Here is my user in the database ( MySQL):

user in database

And finally, this is the result of the test in postman :

Test in Postman

3

There are 3 best solutions below

1
On

Try sending your credentials using Authorization tab in postman, select authorization type to basic Authenter image description here.

0
On

I do the following steps with my Spring Boot app that has Spring Security. Note than my set up is most likely different from yours but the key here is the csfr token.

These are the steps I am following to do the login in Postman:

  1. Start my Server
  2. Open a chrome tab and go to developer tools and then the Network tab.
  3. In the Network tab, I go to the DOC tab.
  4. I then enter the url: http://localhost:9005/mywarehouse and press enter
  5. This takes me to the Login Form where I then click on Create User
  6. After the user is created I am taken back to the login form and login with the new user credentials.
  7. In Postman, I submit a GET request such as http://localhost:9005/mywarehouse/products which returns the HTML of my login form instead of JSON.
  8. Now back in chrome developer tab on the Doc tab I go to the last entry which is my login and I right click on it and select "Copy as cURL (bash)"
  9. I then go back into Postman and click on the Import button and select "raw text" and then paste.
  10. I then click on Continue and then Import. This opens up a new tab with a POST request and I click on send.
  11. This returns HTML code. I locate the csfr token and copy it and then go to the Body tab and replace the csfr token that is currently there with the one returned from the HTML.
  12. I then resend the POST request created by the Import and then I go back to my original GET request tab and resend and this time I get the JSON response I was expecting.
0
On

I have faced this same issue and I got a solution.

In postman go to the settings --> In General section --> turn off the automatically follow redirects.

enter image description here