Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot Data Rest JPA - Entity custom create (User)

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.

like image 874
Christos Baziotis Avatar asked Jul 14 '15 12:07

Christos Baziotis


People also ask

How can we create a custom repository in Spring Data JPA?

We just need to let EmployeeRepository implement the custom interface and define the implementation for the customized repository. Following this design, we can easy to apply query-by-example, the query-method as well as other Spring Data JPA features. You might wonder where we put the @Repository annotation.


2 Answers

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.

like image 71
Christos Baziotis Avatar answered Sep 24 '22 06:09

Christos Baziotis


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.

like image 39
hzpz Avatar answered Sep 23 '22 06:09

hzpz