I am trying to learn Spring. I created a project with Spring Boot using the following tools:
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:
+----+---------------------+-----------+----------+----------+------+ | 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.
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.
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.
If you want Spring to use your constructor, you need to
@JsonProperty
like thispublic 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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With