Golang中字节切片的比较方法
Golang中字节切片的比较方法
我有一个HTML表单(用户名和密码),使用MySQL数据库并将用户密码存储为varchar类型。我使用 bcrypt.GenerateFromPassword 加密密码,然后使用 hex.EncodeToString 将字节切片转换为字符串,最后将密码插入数据库。在"登录"页面上也有HTML输入框(用户邮箱和密码),我执行SQL查询获取密码,接着使用 hex.DecodeString 将密码转换为字节切片,然后将用户输入(登录页面)也转换为字节切片并进行比较。问题是它们不匹配。请解释原因,并提供更好的实现方法。顺便说一句,我使用 bcrypt.CompareHashAndPassword 来比较字节。
func main() {
fmt.Println("hello world")
}
更多关于Golang中字节切片的比较方法的实战教程也可以访问 https://www.itying.com/category-94-b0.html
能否提供一个代码示例?
一个能展示你问题的最小化示例?
在示例中直接使用硬编码密码即可。
更多关于Golang中字节切片的比较方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
哦,我想我明白你的意思了,我只需要将数据库中加密的密码作为第一个参数发送,第二个参数可以这样做:[]byte(用户从登录页面输入的密码)
[]byte(user’sEnteredPasswordFromLoginPage)
引用 Akezhan_Esbolatov:
err = bcrypt.CompareHashAndPassword(decrPass, encryptPassword )
该函数的第一个参数接收哈希值,第二个参数接收明文密码。你不需要自行加密。
文档说明(重点强调):
CompareHashAndPassword 将 bcrypt 哈希密码与其可能的明文等价内容进行比较。成功时返回 nil,失败时返回错误。
-
我不确定你为什么要进行
hex.EncodeToString这个操作。string(hash)就能提供一个很好的、可存储的字符串表示形式,之后你可以直接复用这个字符串。 -
以下代码对我来说是可行的:
package main
import (
"fmt"
"golang.org/x/crypto/bcrypt"
)
func main() {
hash, _ := bcrypt.GenerateFromPassword([]byte("Secret"), bcrypt.MinCost)
fmt.Println(string(hash), err)
fmt.Println(bcrypt.CompareHashAndPassword(hash, []byte("Secret")))
}
我获取用户密码
password := r.FormValue("userPassword")
加密后通过十六进制将字节切片转换为字符串
encryptPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.MinCost)
if err != nil {
http.Error(w, "Server error", http.StatusInternalServerError)
return
}
hexPass := hex.EncodeToString(encryptPassword)
插入数据库
stmt, es := db.Prepare("INSERT INTO userinfo VALUES(?,?,?,?,?,?)")
if es != nil {
panic(es.Error())
}
_, er := stmt.Exec(email, firstName, lastName, hexPass, age, "Bayzakova 116")
if er != nil {
panic(er.Error())
}
这是注册页面
现在登录页面
loginPassword := r.FormValue("userPassword")
获取用户密码
encryptPassword, err := bcrypt.GenerateFromPassword([]byte(loginPassword), bcrypt.MinCost)
if err != nil {
http.Error(w, "Server error", http.StatusInternalServerError)
return
}
加密用户输入的密码
rows, err := db.Query("SELECT userPassword FROM userinfo WHERE userEmail=?", loginEmail)
defer rows.Close()
if err != nil {
panic("retard from select query")
}
var userPassword string
for rows.Next() {
if err := rows.Scan(&userPassword); err != nil {
log.Fatal(err)
}
fmt.Printf("Akezhan %s\n", userPassword)
}
if err := rows.Err(); err != nil {
log.Fatal(err)
}
从数据库获取用户密码
decrPass, err := hex.DecodeString(userPassword)
if err != nil {
panic("retard alert in decoding")
}
从数据库解码密码
err = bcrypt.CompareHashAndPassword(decrPass, encryptPassword)
if err != nil {
http.Error(w, "用户名和/或密码不匹配", http.StatusForbidden)
return
}
现在比较登录页面用户输入的密码和数据库中的密码
问题在于你使用了 hex.EncodeToString 和 hex.DecodeString 来处理密码哈希值,这会导致数据转换不一致。bcrypt.GenerateFromPassword 返回的字节切片已经包含了完整的哈希信息,直接将其转换为十六进制字符串再转换回来可能会破坏原始数据。
正确的做法是直接使用 bcrypt.CompareHashAndPassword 来比较哈希密码和明文密码,无需手动转换。
以下是正确的实现示例:
package main
import (
"golang.org/x/crypto/bcrypt"
)
// 注册时生成密码哈希
func register(password string) (string, error) {
// 直接生成密码哈希
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return "", err
}
// 将字节切片直接转换为字符串存储到数据库
return string(hashedPassword), nil
}
// 登录时验证密码
func login(storedPasswordHash string, inputPassword string) error {
// 直接从数据库读取的字符串转换为字节切片
hashedPassword := []byte(storedPasswordHash)
// 使用 bcrypt 内置的比较函数
return bcrypt.CompareHashAndPassword(hashedPassword, []byte(inputPassword))
}
// 使用示例
func main() {
// 注册用户
password := "myPassword123"
hashed, err := register(password)
if err != nil {
panic(err)
}
// 模拟存储到数据库
storedHash := hashed
// 登录验证
err = login(storedHash, "myPassword123")
if err == nil {
println("密码正确")
} else {
println("密码错误:", err.Error())
}
// 错误密码测试
err = login(storedHash, "wrongPassword")
if err != nil {
println("密码验证失败:", err.Error())
}
}
关键点说明:
bcrypt.GenerateFromPassword返回的字节切片可以直接转换为字符串存储bcrypt.CompareHashAndPassword会自动处理哈希比较的所有细节- 无需使用
hex.EncodeToString和hex.DecodeString进行额外转换
如果你的数据库字段类型是 varchar,确保它有足够的长度来存储完整的 bcrypt 哈希值(通常至少 60 个字符)。

