英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论