【发布时间】:2017-10-07 06:07:52
【问题描述】:
我正在使用 Spring Boot 为在线商店在 java 中创建一个 REST API,我想将用户密码安全地存储在数据库中, 为此,我使用 Spring Security 附带的 BCrypt,我使用 MySQL 和 JPA-Hibernate 进行持久性。
我正在按如下方式实现它:
这是用户实体:
@Entity
@SelectBeforeUpdate
@DynamicUpdate
@Table (name = "USER")
public class User {
@Id
@GeneratedValue
@Column(name = "USER_ID")
private Long userId;
@Column(name = "ALIAS")
private String alias;
@Column(name = "NAME")
private String name;
@Column(name = "LAST_NAME")
private String lastName;
@Column(name = "TYPE")
private String type;
@Column(name = "PASSWORD")
private String password;
public String getPassword() {
return password;
}
/**
* When adding the password to the user class the setter asks if it is necessary or not to add the salt,
* if this is necessary the method uses the method BCrypt.hashpw (password, salt),
* if it is not necessary to add the salt the string That arrives is added intact
*/
public void setPassword(String password, boolean salt) {
if (salt) {
this.password = BCrypt.hashpw(password, BCrypt.gensalt());
} else {
this.password = password;
}
}
//Setters and Getters and etc.
}
这是用户类的存储库:
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}
这是用户类的服务:
@Service
public class UserService{
private UserRepository userRepository;
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public User addEntity(User user) {
//Here we tell the password setter to generate the salt
user.setPassword(user.getPassword(), true);
return userRepository.save(user);
}
public User updateEntity(User user) {
User oldUser = userRepository.findOne(user.getUserId());
/*
*This step is necessary to maintain the same password since if we do not do this
*in the database a null is generated in the password field,
*this happens since the JSON that arrives from the client application does not
*contain the password field, This is because to carry out the modification of
*the password a different procedure has to be performed
*/
user.setPassword(oldUser.getPassword(), false);
return userRepository.save(user);
}
/**
* By means of this method I verify if the password provided by the client application
* is the same as the password that is stored in the database which is already saved with the salt,
* returning a true or false boolean depending on the case
*/
public boolean isPassword(Object password, Long id) {
User user = userRepository.findOne(id);
//To not create an entity that only has a field that says password, I perform this mapping operation
String stringPassword = (String)((Map)password).get("password");
//This method generates boolean
return BCrypt.checkpw(stringPassword, user.getPassword());
}
/**
*This method is used to update the password in the database
*/
public boolean updatePassword(Object passwords, Long id) {
User user = userRepository.findOne(id);
//Here it receive a JSON with two parameters old password and new password, which are transformed into strings
String oldPassword = (String)((Map)passwords).get("oldPassword");
String newPassword = (String)((Map)passwords).get("newPassword");
if (BCrypt.checkpw(oldPassword, user.getPassword())){
//If the old password is the same as the one currently stored in the database then the new password is updated
//in the database for this a new salt is generated
user.setPassword(newPassword, true);
//We use the update method, passing the selected user
updateEntity(user);
//We return a true boolean
return true;
}else {
//If the old password check fails then we return a false boolean
return false;
}
}
//CRUD basic methods omitted because it has no case for the question
}
这是公开 API 端点的控制器:
@RestController
@CrossOrigin
@RequestMapping("/api/users")
public class UserController implements{
UserService userService;
@Autowired
public UserController(UserService userService) {
this.userService = userService;
}
@RequestMapping( value = "", method = RequestMethod.POST )
public User addEntity(@RequestBody User user) {
return userService.addEntity(user);
}
@RequestMapping( value = "", method = RequestMethod.PUT )
public User updateEntity(@RequestBody User user) {
return userService.updateEntity(user);
}
@RequestMapping( value = "/{id}/checkPassword", method = RequestMethod.POST )
public boolean isPassword(@PathVariable(value="id") Long id, @RequestBody Object password) {
return userService.isPassword(password, id);
}
@RequestMapping( value = "/{id}/updatePassword", method = RequestMethod.POST )
public boolean updatePassword(@PathVariable(value="id") Long id, @RequestBody Object password) {
return userService.updatePassword(password, id);
}
}
这是我的问题所在,我的方法有效,但我觉得这不是最好的方法,我不喜欢更改密码设置器 我希望保留设置器的标准形式,就像在用户服务中一样我认为有机会以不同方式处理用户和密码更新,因此请尝试在实体中使用 @DynamicUpdate 注释,但它根本无法正常工作,因为更新中未提供字段而不是保留它们被保存像空值。
我正在寻找的是使用 Spring Boot 处理密码安全性的更好方法。
【问题讨论】:
标签: java jpa spring-boot spring-security salt