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

6 回复

能否提供一个代码示例?

一个能展示你问题的最小化示例?

在示例中直接使用硬编码密码即可。

更多关于Golang中字节切片的比较方法的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


哦,我想我明白你的意思了,我只需要将数据库中加密的密码作为第一个参数发送,第二个参数可以这样做:[]byte(用户从登录页面输入的密码)

[]byte(user’sEnteredPasswordFromLoginPage)

引用 Akezhan_Esbolatov:

err = bcrypt.CompareHashAndPassword(decrPass, encryptPassword )

该函数的第一个参数接收哈希值,第二个参数接收明文密码。你不需要自行加密。

文档说明(重点强调):

CompareHashAndPassword 将 bcrypt 哈希密码与其可能的明文等价内容进行比较。成功时返回 nil,失败时返回错误。

  1. 我不确定你为什么要进行 hex.EncodeToString 这个操作。string(hash) 就能提供一个很好的、可存储的字符串表示形式,之后你可以直接复用这个字符串。

  2. 以下代码对我来说是可行的:

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.EncodeToStringhex.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())
    }
}

关键点说明:

  1. bcrypt.GenerateFromPassword 返回的字节切片可以直接转换为字符串存储
  2. bcrypt.CompareHashAndPassword 会自动处理哈希比较的所有细节
  3. 无需使用 hex.EncodeToStringhex.DecodeString 进行额外转换

如果你的数据库字段类型是 varchar,确保它有足够的长度来存储完整的 bcrypt 哈希值(通常至少 60 个字符)。

回到顶部