Golang中Bcrypt密码不匹配问题如何解决
Golang中Bcrypt密码不匹配问题如何解决
当我从MySQL数据库获取哈希密码并与请求负载进行比较时,函数bcrypt.CompareHashAndPassword返回false。以下是代码,有人能帮助我吗?
哈希函数: 包 hasher
import (
"golang.org/x/crypto/bcrypt"
)
// HashPassword 函数
func HashPassword(password string) (string, error) {
bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
return string(bytes), err
}
// CheckPasswordHash 函数
func CheckPasswordHash(password, hash string) bool {
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
return err == nil
}
创建会话的方法: 包 session
import (
"encoding/json"
"fmt"
"io/ioutil"
"net/http"
"github.com/kielkow/Post-Service/shared/http/cors"
"github.com/kielkow/Post-Service/shared/providers/apperror"
"github.com/kielkow/Post-Service/shared/providers/authentication"
"github.com/kielkow/Post-Service/shared/providers/hasher"
)
const sessionBasePath = "session"
// SetupRoutes 函数
func SetupRoutes(apiBasePath string) {
handleSession := http.HandlerFunc(postsHandler)
http.Handle(fmt.Sprintf("%s/%s", apiBasePath, sessionBasePath), cors.Middleware(handleSession))
}
func postsHandler(w http.ResponseWriter, r *http.Request) {
switch r.Method {
case http.MethodPost:
var session Session
bodyBytes, err := ioutil.ReadAll(r.Body)
if err != nil {
error := apperror.GenerateError(400, err.Error())
w.WriteHeader(http.StatusBadRequest)
w.Write(error)
return
}
err = json.Unmarshal(bodyBytes, &session)
if err != nil {
error := apperror.GenerateError(400, err.Error())
w.WriteHeader(http.StatusBadRequest)
w.Write(error)
return
}
passwordHashed, err := getPassword(session.Email)
if err != nil {
error := apperror.GenerateError(403, err.Error())
w.WriteHeader(http.StatusNonAuthoritativeInfo)
w.Write(error)
return
}
match := hasher.CheckPasswordHash(session.Password, passwordHashed)
if match == false {
error := apperror.GenerateError(403, "Incorret credentials")
w.WriteHeader(http.StatusNonAuthoritativeInfo)
w.Write(error)
return
}
token, err := authentication.GenerateJWT(session.Email)
tokenJSON, err := json.Marshal(token)
w.Header().Set("Content-Type", "application/json")
w.Write(tokenJSON)
return
case http.MethodOptions:
return
}
}
更多关于Golang中Bcrypt密码不匹配问题如何解决的实战教程也可以访问 https://www.itying.com/category-94-b0.html
2 回复
@kielkow 你最终解决这个问题了吗?
更多关于Golang中Bcrypt密码不匹配问题如何解决的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
问题通常出现在密码哈希的存储或比较环节。以下是可能导致bcrypt密码不匹配的常见原因及解决方案:
1. 数据库字段长度问题
确保MySQL中存储哈希密码的字段足够长,bcrypt哈希值通常是60个字符:
ALTER TABLE users MODIFY password_hash VARCHAR(255);
2. 哈希值存储问题
检查从数据库获取密码哈希的getPassword函数:
func getPassword(email string) (string, error) {
var passwordHash string
err := db.QueryRow("SELECT password_hash FROM users WHERE email = ?", email).Scan(&passwordHash)
if err != nil {
return "", err
}
// 调试输出,查看实际获取的哈希值
fmt.Printf("从数据库获取的哈希值: %s\n", passwordHash)
fmt.Printf("哈希值长度: %d\n", len(passwordHash))
return passwordHash, nil
}
3. 密码哈希创建时的检查
在创建用户时验证哈希过程:
func createUserHandler(w http.ResponseWriter, r *http.Request) {
// ... 解析请求
// 生成哈希
hashedPassword, err := hasher.HashPassword(user.Password)
if err != nil {
// 处理错误
}
// 调试输出
fmt.Printf("生成的哈希值: %s\n", hashedPassword)
fmt.Printf("哈希值长度: %d\n", len(hashedPassword))
// 立即验证
match := hasher.CheckPasswordHash(user.Password, hashedPassword)
fmt.Printf("立即验证结果: %v\n", match)
// 存储到数据库
// ...
}
4. 直接调试比较函数
添加详细的调试信息到会话处理器:
func postsHandler(w http.ResponseWriter, r *http.Request) {
// ... 之前的代码
passwordHashed, err := getPassword(session.Email)
if err != nil {
// 处理错误
}
// 调试信息
fmt.Printf("请求密码: %s\n", session.Password)
fmt.Printf("数据库哈希: %s\n", passwordHashed)
fmt.Printf("哈希长度: %d\n", len(passwordHashed))
// 直接使用bcrypt比较进行调试
err = bcrypt.CompareHashAndPassword([]byte(passwordHashed), []byte(session.Password))
if err != nil {
fmt.Printf("bcrypt比较错误: %v\n", err)
// 返回错误
}
// ... 其余代码
}
5. 检查数据库编码问题
确保数据库连接使用正确的字符集:
// 数据库连接字符串添加字符集参数
dsn := "user:password@tcp(127.0.0.1:3306)/database?charset=utf8mb4&parseTime=True&loc=Local"
db, err := sql.Open("mysql", dsn)
6. 验证哈希格式
添加一个验证函数检查哈希格式:
func isValidBcryptHash(hash string) bool {
// bcrypt哈希以 $2a$, $2b$, $2x$ 或 $2y$ 开头
if len(hash) < 60 {
return false
}
prefix := hash[:4]
validPrefixes := []string{"$2a$", "$2b$", "$2x$", "$2y$"}
for _, p := range validPrefixes {
if strings.HasPrefix(hash, p) {
return true
}
}
return false
}
// 在比较前使用
if !isValidBcryptHash(passwordHashed) {
fmt.Println("无效的bcrypt哈希格式")
// 处理错误
}
7. 完整示例修复
如果问题仍然存在,尝试这个最小化的测试用例:
package main
import (
"fmt"
"golang.org/x/crypto/bcrypt"
)
func main() {
password := "myPassword123"
// 生成哈希
hash, err := bcrypt.GenerateFromPassword([]byte(password), 14)
if err != nil {
panic(err)
}
hashStr := string(hash)
fmt.Printf("生成的哈希: %s\n", hashStr)
// 模拟从数据库获取(确保没有额外空格或换行)
dbHash := hashStr // 在实际中从数据库获取
// 比较
err = bcrypt.CompareHashAndPassword([]byte(dbHash), []byte(password))
if err != nil {
fmt.Printf("比较失败: %v\n", err)
} else {
fmt.Println("密码匹配成功")
}
}
运行这个测试来确定你的bcrypt实现是否正确工作。如果测试通过但你的代码不工作,问题可能出在数据库存储或检索过程中。

