go - BeforeSave 不填充数据
问题描述
我有以下代码,一个非常简单的模型User
,我正在尝试更新现有用户的密码;但是,在 中BeforeSave
,我无法u *User
填充数据,所以第一次创建时,密码是散列的,但是当我更新它时,密码变成纯文本。有什么想法我在这里做错了吗?
package main
import (
"fmt"
"golang.org/x/crypto/bcrypt"
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
type User struct {
gorm.Model
Username string `gorm:"type:varchar(40);unique" json:"username,omitempty"`
Password string `gorm:"size:255" json:"password,omitempty"`
NickName string `gorm:"type:varchar(32)" json:"nick_name,omitempty"`
}
func MakePassword(password string) (string, error) {
bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
return string(bytes), err
}
// BeforeSave : hook before a user is saved
func (u *User) BeforeSave(tx *gorm.DB) (err error) {
fmt.Println("================= user: ", u)
if u.Password != "" {
hash, err := MakePassword(u.Password)
if err != nil {
return nil
}
tx.Statement.SetColumn("password", hash)
}
return
}
func main() {
var connectionString = fmt.Sprintf(
"%s:%s@/%s?charset=utf8&parseTime=True&loc=Local",
"root", "password", "myproject",
)
db, _ := gorm.Open(mysql.Open(connectionString), &gorm.Config{})
db.AutoMigrate(&User{})
db.Save(&User{
Username: "username",
Password: "123",
})
// Up to this point, everything works, password is hashed.
// the following does not work as I expected
userMap := make(map[string]interface{})
userMap["id"] = 1
userMap["password"] = "new_password"
db.Model(&User{}).Where(&User{
Model: gorm.Model{ID: uint(userMap["id"].(int))},
}).Updates(userMap)
}
解决方案
问题可能是您的 if 语句:if u.Password != ""
. 使用地图更新时,我几乎可以肯定会使用空模型,因此u.Password
将是空的。
我这样做是用BeforeCreate
而BeforeUpdate
不是BeforeSave
:
func (u *User) BeforeCreate(tx *gorm.DB) error {
return u.bcryptPassword(tx)
}
func (u *User) BeforeUpdate(tx *gorm.DB) error {
if tx.Statement.Changed("Password") {
return u.bcryptPassword(tx)
}
return nil
}
func (u *User) bcryptPassword(tx *gorm.DB) error {
var newPass string
switch u := tx.Statement.Dest.(type) {
case map[string]interface{}:
newPass = u["password"].(string)
case *User:
newPass = u.Password
case []*User:
newPass = u[tx.Statement.CurDestIndex].Password
}
b, err := bcrypt.GenerateFromPassword([]byte(newPass), 10)
if err != nil {
return err
}
tx.Statement.SetColumn("password", b)
return nil
}
你应该依赖给定的 gorm 事务,而不是你的u
变量。
注意:此实现也适用于批处理操作和使用映射而不是结构的插入/更新。
推荐阅读
- matplotlib - matplotlib 绘图在 vscode 中静默失败,但在同一环境中从 python 解释器工作
- python - 计算 Pagerank 的百分比
- c# - 如何在 WebApi Core 中使用 Unauthorized() 获取空的 http 正文
- azure-ad-b2c - B2C 在登录 REST API 期间不发送电子邮件
- css - Elementor 瞄准运动 CSS 变量
- firebase - Flutter firebase web google登录错误
- azure-data-factory - 如何在 Azure 数据工厂复制工具中动态更改 REST API URL?
- macos - 为什么我在终端中看不到我的应用程序?
- python - 从 optgroup 中选择选项
- css - css:在 youtube embed 上创建颜色叠加层