I have a Go application with GORM and I'm trying to hash Users' password fields every time they are updated.
To achieve this I'm using the BeforeUpdate
hook provided by GORM. The problem that I'm facing is that on the said hook the Password
field for the user (u.password
) has the old hashed password value that is already stored on the DB instead of the newPassword
value that I'm updating it with. So when I hash the password on the hook, I'm really just hashing the the already hashed old password.
My BeforeUpdate
hook:
func (u *User) BeforeUpdate(tx *gorm.DB) (err error) {
if (tx.Statement.Changed("Password")) {
bytePassword := []byte(u.Password) // Old password value here!
passwordHash, err := bcrypt.GenerateFromPassword(bytePassword, bcrypt.DefaultCost)
if (err != nil) { return err }
tx.Statement.SetColumn("password", string(passwordHash))
}
return nil
}
And the update is triggered like this:
var user models.User
err := db.First(&user, id).Error
if (err != nil) { log.Fatal(err) }
// Not sure how to access this "newPassword" value on the "BeforeUpdate" hook
err = db.Model(&user).Update("password", newPassword).Error
if (err != nil) { log.Fatal(err) }
Edit: Working solution thanks to @s3vt's answer
Just had to change my BeforeUpdate
hook:
func (u *User) BeforeUpdate(tx *gorm.DB) (err error) {
if (tx.Statement.Changed("Password")) {
u.Password = tx.Statement.Dest.(map[string]interface{})["password"].(string)
bytePassword := []byte(u.Password)
passwordHash, err := bcrypt.GenerateFromPassword(bytePassword, bcrypt.DefaultCost)
if (err != nil) { return err }
tx.Statement.SetColumn("password", string(passwordHash))
}
return nil
}
CodePudding user response:
You can get the new password value form the tx.Statement.Dest
map.
This is the same map that SetColumn
updates the value to.
OR set the new password value before the actual update call.
user.Password = newPassword
err = db.Model(&user).Updates(&user).Error
In this case old password will not be available at the hook.