在MySQL中存储bcrypt生成的字节切片,最合适的方式是将其转换为Base64编码的字符串存储。bcrypt生成的哈希值包含salt和哈希结果,直接存储为字符串是标准做法。
以下是完整的示例代码:
package main
import (
"database/sql"
"encoding/base64"
"fmt"
"log"
"golang.org/x/crypto/bcrypt"
_ "github.com/go-sql-driver/mysql"
)
// 用户注册时存储密码
func storePassword(db *sql.DB, username, plainPassword string) error {
// 使用bcrypt生成密码哈希
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(plainPassword), bcrypt.DefaultCost)
if err != nil {
return err
}
// 将字节切片转换为Base64字符串存储
encodedPassword := base64.StdEncoding.EncodeToString(hashedPassword)
// 存储到数据库
_, err = db.Exec("INSERT INTO users (username, password) VALUES (?, ?)", username, encodedPassword)
return err
}
// 用户登录时验证密码
func verifyPassword(db *sql.DB, username, plainPassword string) (bool, error) {
var encodedPassword string
err := db.QueryRow("SELECT password FROM users WHERE username = ?", username).Scan(&encodedPassword)
if err != nil {
return false, err
}
// 从Base64字符串解码回字节切片
hashedPassword, err := base64.StdEncoding.DecodeString(encodedPassword)
if err != nil {
return false, err
}
// 使用bcrypt比较密码
err = bcrypt.CompareHashAndPassword(hashedPassword, []byte(plainPassword))
if err != nil {
if err == bcrypt.ErrMismatchedHashAndPassword {
return false, nil
}
return false, err
}
return true, nil
}
// 创建用户表(如果需要)
func createTable(db *sql.DB) error {
_, err := db.Exec(`
CREATE TABLE IF NOT EXISTS users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(255) UNIQUE NOT NULL,
password TEXT NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
`)
return err
}
func main() {
// 连接数据库
db, err := sql.Open("mysql", "username:password@tcp(localhost:3306)/database_name")
if err != nil {
log.Fatal(err)
}
defer db.Close()
// 创建表
err = createTable(db)
if err != nil {
log.Fatal(err)
}
// 示例:存储用户密码
err = storePassword(db, "john_doe", "mysecretpassword")
if err != nil {
log.Fatal(err)
}
// 示例:验证用户密码
isValid, err := verifyPassword(db, "john_doe", "mysecretpassword")
if err != nil {
log.Fatal(err)
}
fmt.Printf("Password verification result: %t\n", isValid)
}
数据库表结构建议:
CREATE TABLE users (
id INT AUTO_INCREMENT PRIMARY KEY,
username VARCHAR(255) UNIQUE NOT NULL,
password TEXT NOT NULL, -- 存储Base64编码的bcrypt哈希
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
这种方式有几个优势:
- Base64编码确保所有字节都能安全存储在TEXT字段中
- 保持了bcrypt哈希的完整性
- 便于后续的密码验证操作
- 符合安全最佳实践
在MySQL中,建议使用TEXT类型字段来存储Base64编码后的字符串,因为bcrypt哈希的长度是固定的60字节,Base64编码后约为80-88个字符。