Go GORM – 在更新之前,字段具有旧值

huangapple go评论81阅读模式
英文:

Go GORM - BeforeUpdate fields have old values

问题

我有一个使用GORM的Go应用程序,我正在尝试在每次更新用户密码字段时对其进行哈希处理。

为了实现这一点,我使用了GORM提供的BeforeUpdate钩子。我面临的问题是,在该钩子中,用户的Password字段(u.password)具有已经存储在数据库中的旧哈希密码值,而不是我正在使用的newPassword值。因此,当我在钩子中对密码进行哈希处理时,实际上只是对已经哈希处理过的旧密码进行再次哈希处理。

我的BeforeUpdate钩子代码如下:

func (u *User) BeforeUpdate(tx *gorm.DB) (err error) {
  if (tx.Statement.Changed("Password")) {
    bytePassword := []byte(u.Password) // 这里是旧密码值!
    passwordHash, err := bcrypt.GenerateFromPassword(bytePassword, bcrypt.DefaultCost)
    if (err != nil) { return err }
    tx.Statement.SetColumn("password", string(passwordHash))
  }
  return nil
}

更新操作的触发方式如下:

var user models.User
err := db.First(&user, id).Error
if (err != nil) { log.Fatal(err) }
// 不确定如何在“BeforeUpdate”钩子中访问“newPassword”值
err = db.Model(&user).Update("password", newPassword).Error
if (err != nil) { log.Fatal(err) }

编辑:感谢@s3vt的答案,问题已解决

只需更改我的BeforeUpdate钩子:

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
}
英文:

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
}

答案1

得分: 1

你可以从tx.Statement.Dest映射中获取新的密码值。这个映射与SetColumn更新的值相同。

或者,在实际更新调用之前设置新的密码值。

user.Password = newPassword
err = db.Model(&user).Updates(&user).Error

在这种情况下,旧密码将不会在钩子函数中可用。

英文:

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.

huangapple
  • 本文由 发表于 2022年8月31日 09:56:17
  • 转载请务必保留本文链接:https://go.coder-hub.com/73550140.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定