Golang中如何将字节数组字段填充到Cloud Firestore并与[]bytes字段交互
Golang中如何将字节数组字段填充到Cloud Firestore并与[]bytes字段交互 大家好
我正在学习使用 Golang 进行 Web 开发,并尝试理解如何在 Cloud Firestore 数据库中存储密码。
密码已按如下方式保存:
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), 12)
docRef, _, err := m.Client.Collection("users").Add(context.Background(), map[string]interface{}{
"name": name,
"email": email,
"password": hashedPassword, // 这是一个 []byte
"created": time.Now(),
})
然后当我从 Firestore 获取用户数据并打印时,密码似乎被转换为了 []uint8,可能是由 Firestore 驱动完成的。所以这个命令:
log.Printf("> Document data: %#v", ds.Data())
输出:
> Document data: map[string]interface {}{"created":time.Date(2022, time.April, 3, 17, 33, 36, 270361000, time.UTC), "email":"test@test.com", "name":"Junior", "password":[]uint8{0x24, 0x32, 0x61, 0x24, 0x31, 0x32, 0x24, 0x37, 0x68, 0x6b, 0x43, 0x38, 0x39, 0x54, 0x68, 0x31, 0x77, 0x63, 0x31, 0x52, 0x69, 0x57, 0x4e, 0x37, 0x6d, 0x31, 0x6b, 0x7a, 0x75, 0x64, 0x72, 0x6c, 0x38, 0x45, 0x71, 0x71, 0x54, 0x62, 0x30, 0x44, 0x6b, 0x4c, 0x65, 0x63, 0x51, 0x4c, 0x45, 0x35, 0x42, 0x45, 0x55, 0x61, 0x77, 0x4a, 0x54, 0x48, 0x2e, 0x62, 0x61, 0x32}}
接下来,当我尝试映射到我的 User 结构体时,不知何故 HashedPassword 字段总是空的 []:
type User struct {
Id string
Name string
Email string
HashedPassword []byte
Created time.Time
}
user := &models.User{}
user.Id = ds.Ref.ID
ds.DataTo(&user) // 这不会填充 HashedPassword 字段
log.Printf("\n>>>> hashed: %+v\n", user.HashedPassword)
输出:
>>>> hashed: []
我为了获取填充了 HashPassword 字段的 User 结构体而采用的变通方法是:
func ToByteSlice(b []byte) []byte {
return b
}
user := &models.User{}
user.Id = ds.Ref.ID
user.HashedPassword = ToByteSlice(ds.Data()["password"].([]uint8))
ds.DataTo(&user)
log.Printf("\n>>>> hashed: %+v\n", user.HashedPassword) // 现在 []byte 被填充了
输出:
>>>> hashed: [36 50 97 36 49 50 36 68 111 105 109 80 84 113 57 73 112 102 111 97 86 104 54 88 85 77 72 100 46 51 55 116 110 49 100 81 49 89 83 113 53 82 71 122 112 114 106 100 82 47 90 51 118 55 122 77 116 81 100 54]
我想知道这里是否有人遇到过类似的情况,以及在保存和检索哈希密码时有什么建议。谢谢
更多关于Golang中如何将字节数组字段填充到Cloud Firestore并与[]bytes字段交互的实战教程也可以访问 https://www.itying.com/category-94-b0.html
更多关于Golang中如何将字节数组字段填充到Cloud Firestore并与[]bytes字段交互的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
在Golang中,Cloud Firestore驱动会将[]byte类型存储为[]uint8,这是Go内部对字节切片的表示方式。当你使用DataTo()方法时,需要确保结构体字段类型与Firestore存储的类型完全匹配。
以下是正确的处理方式:
// 定义User结构体,注意HashedPassword字段类型
type User struct {
Id string `firestore:"-"`
Name string `firestore:"name"`
Email string `firestore:"email"`
HashedPassword []byte `firestore:"password"`
Created time.Time `firestore:"created"`
}
// 存储用户数据
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), 12)
if err != nil {
log.Fatal(err)
}
user := User{
Name: name,
Email: email,
HashedPassword: hashedPassword,
Created: time.Now(),
}
// 直接存储结构体
docRef, _, err := m.Client.Collection("users").Add(context.Background(), user)
if err != nil {
log.Fatal(err)
}
// 检索数据时使用正确的类型转换
doc, err := m.Client.Collection("users").Doc(docID).Get(context.Background())
if err != nil {
log.Fatal(err)
}
var user User
if err := doc.DataTo(&user); err != nil {
log.Fatal(err)
}
// 现在HashedPassword字段会被正确填充
fmt.Printf("Hashed password: %v\n", user.HashedPassword)
// 验证密码
err = bcrypt.CompareHashAndPassword(user.HashedPassword, []byte(password))
if err != nil {
fmt.Println("Password does not match")
} else {
fmt.Println("Password matches")
}
如果你需要处理已经存储的数据,可以使用类型断言:
doc, err := m.Client.Collection("users").Doc(docID).Get(context.Background())
if err != nil {
log.Fatal(err)
}
data := doc.Data()
user := User{
Id: doc.Ref.ID,
Name: data["name"].(string),
Email: data["email"].(string),
Created: data["created"].(time.Time),
}
// 类型断言处理字节数组
if pwd, ok := data["password"].([]byte); ok {
user.HashedPassword = pwd
} else if pwd, ok := data["password"].([]uint8); ok {
// Firestore返回的是[]uint8,需要转换为[]byte
user.HashedPassword = []byte(pwd)
}
fmt.Printf("User: %+v\n", user)
对于密码验证操作:
// 验证密码函数
func VerifyPassword(storedHash interface{}, password string) error {
var hash []byte
switch v := storedHash.(type) {
case []byte:
hash = v
case []uint8:
hash = []byte(v)
default:
return fmt.Errorf("unexpected type for password hash: %T", v)
}
return bcrypt.CompareHashAndPassword(hash, []byte(password))
}
// 使用示例
err = VerifyPassword(doc.Data()["password"], inputPassword)
if err != nil {
fmt.Println("Authentication failed:", err)
} else {
fmt.Println("Authentication successful")
}
关键点是:Firestore驱动在存储和检索时会保持[]byte和[]uint8之间的兼容性,但在使用DataTo()进行自动映射时,需要确保结构体字段类型与存储的数据类型完全匹配。

