5

I am trying to learn Spring. I created a project with Spring Boot using the following tools:

  • Spring Data JPA
  • Spring Data REST
  • Spring HATEOAS
  • Spring Security

I am trying to create a User entity. I want the user to have an encrypted password (+ salt).

When i do POST to /api/users i successfully create a new user.

{
"firstname":"John",
"lastname":"Doe",
"email":"[email protected]",
"password":"12345678"
}

But i have 2 problems:

  • the password is saved in clear-text
  • the salt is null
+----+---------------------+-----------+----------+----------+------+
| id |        email        | firstname | lastname | password | salt |
+----+---------------------+-----------+----------+----------+------+
|  1 | [email protected] | John      | Doe      | 12345678 | NULL |
+----+---------------------+-----------+----------+----------+------+

The problem i think is that the default constructor is used and not the other one i have created. I am new to Spring and JPA so i must be missing something. Here is my code.

User.java

@Entity
@Table(name = "users")
public class User{

    @Id
    @GeneratedValue
    private Long id;

    @Column(nullable = false)
    public String firstname;

    @Column(nullable = false)
    public String lastname;

    @Column(nullable = false, unique = true)
    public String email;

    @JsonIgnore
    @Column(nullable = false)
    public String password;

    @JsonIgnore
    @Column
    private String salt;

    public User() {}

    public User(String email, String firstname, String lastname, String password) {
        this.email = email;
        this.firstname = firstname;
        this.lastname = lastname;
        this.salt = UUID.randomUUID().toString();
        this.password = new BCryptPasswordEncoder().encode(password + this.salt);
    }


    @JsonIgnore
    public String getSalt() {
        return salt;
    }

    @JsonProperty
    public void setSalt(String salt) {
        this.salt = salt;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public String getFirstname() {
        return firstname;
    }

    public void setFirstname(String firstname) {
        this.firstname = firstname;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getLastname() {
        return lastname;
    }

    public void setLastname(String lastname) {
        this.lastname = lastname;
    }

    @JsonIgnore
    public String getPassword() {
        return password;
    }

    @JsonProperty
    public void setPassword(String password) {
        this.password = password;
    }

}

UserRepository.java

public interface UserRepository extends JpaRepository<User, Long> {

    public User findByEmail(String email);

    public User findByEmailAndPassword(String email, String password);
}

Application.java

@SpringBootApplication
public class Application {


    public static void main(String[] args) {
        SpringApplication.run(Application .class, args);
    }

}

Also if someone finds what i did wrong, i would like to point me where/how i should put the user login code (decryption).

Thanks.

6
  • where is your REST @RestController? Commented Jul 14, 2015 at 18:06
  • @Makoton i don't have one. Spring Data Rest automatically exposes my entities in a RESTful API. Do i need one in this case? Commented Jul 14, 2015 at 18:09
  • and did you try to create a UserService and : public void registerUser(final User user) { final String encodedPassword = passwordEncoder.encode(user.getPassword()); user.setPassword(encodedPassword); userRepo.save(user); } Commented Jul 14, 2015 at 18:20
  • @Makoton No i did not. I'll do that and post back. Thanks! Commented Jul 14, 2015 at 18:21
  • @agnostos Did you solve your problem? If not, did you try the solution in my answer? Commented Jul 17, 2015 at 15:13

2 Answers 2

3

So, here is how i solved my problem: i created a Controller as my custom endpoint and then i created a service in which i placed the logic i wanted for the creation of the user. Here is the code:

UserController.java

@Controller
public class UserController {

    @Autowired
    private UserService userService;

    @RequestMapping("/api/register")
    @ResponseBody
    public Long register(@RequestBody User user) {
        return userService.registerUser(user);
    }

    ...

}

UserService .java

@Service
public class UserService {

    @Autowired
    private UserRepository userRepository;

    public Long registerUser(User user) {
        user.setPassword(new BCryptPasswordEncoder().encode(password));
        userRepository.save(user);
        return user.getId();
    }

        ...

}

so by doing a POST with

{
"firstname":"John",
"lastname":"Doe",
"email":"[email protected]",
"password":"12345678"
}

in /api/register, i can now create a user with a hashed password.

Sign up to request clarification or add additional context in comments.

Comments

2

If you want Spring to use your constructor, you need to

  • remove the no-argument constructor
  • annotate every parameter in the other constructor with @JsonProperty like this
public User(@JsonProperty("email") String email, 
            @JsonProperty("firstname") String firstname, 
            @JsonProperty("lastname") String lastname, 
            @JsonProperty("password") String password) {
    this.email = email;
    this.firstname = firstname;
    this.lastname = lastname;
    this.password = new BCryptPasswordEncoder().encode(password);
}

You don't need to provide a salt value to the BCryptPasswordEncoder because it already salts passwords by itself.

1 Comment

How do you do when one of the arguments is a reference to another entity? Can @JsonProperty be used then?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.