You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

119 lines
3.2 KiB

// 密码加密
package utils
import (
"errors"
"golang.org/x/crypto/bcrypt"
)
const (
// DefaultCost 默认加密成本,平衡安全性和性能
DefaultCost = bcrypt.DefaultCost // 通常是10
// MinCost 最小加密成本
MinCost = bcrypt.MinCost // 4
// MaxCost 最大加密成本
MaxCost = bcrypt.MaxCost // 31
)
var (
// ErrPasswordTooLong 密码过长错误
ErrPasswordTooLong = errors.New("password is too long")
// ErrPasswordEmpty 密码为空错误
ErrPasswordEmpty = errors.New("password cannot be empty")
// ErrInvalidCost 加密成本无效错误
ErrInvalidCost = errors.New("invalid cost value")
)
// HashPassword 使用bcrypt对密码进行加密
// password: 原始密码
// 返回加密后的密码哈希值和错误信息
func HashPassword(password string) (string, error) {
return HashPasswordWithCost(password, DefaultCost)
}
// HashPasswordWithCost 使用指定成本对密码进行加密
// password: 原始密码
// cost: 加密成本 (4-31),成本越高越安全但速度越慢
// 返回加密后的密码哈希值和错误信息
func HashPasswordWithCost(password string, cost int) (string, error) {
// 验证输入
if password == "" {
return "", ErrPasswordEmpty
}
// bcrypt有72字节的限制
if len(password) > 72 {
return "", ErrPasswordTooLong
}
// 验证成本值
if cost < MinCost || cost > MaxCost {
return "", ErrInvalidCost
}
// 生成密码哈希
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), cost)
if err != nil {
return "", err
}
return string(hashedPassword), nil
}
// CheckPassword 验证密码是否正确
// hashedPassword: 存储的密码哈希值
// password: 用户输入的原始密码
// 返回验证结果
func CheckPassword(hashedPassword, password string) bool {
// 验证输入
if hashedPassword == "" || password == "" {
return false
}
// 比较密码
err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password))
return err == nil
}
// CheckPasswordWithError 验证密码是否正确,返回详细错误信息
// hashedPassword: 存储的密码哈希值
// password: 用户输入的原始密码
// 返回验证结果和错误信息
func CheckPasswordWithError(hashedPassword, password string) error {
// 验证输入
if hashedPassword == "" {
return errors.New("hashed password cannot be empty")
}
if password == "" {
return ErrPasswordEmpty
}
// 比较密码
return bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password))
}
// GetCost 获取密码哈希的加密成本
// hashedPassword: 密码哈希值
// 返回加密成本和错误信息
func GetCost(hashedPassword string) (int, error) {
if hashedPassword == "" {
return 0, errors.New("hashed password cannot be empty")
}
cost, err := bcrypt.Cost([]byte(hashedPassword))
return cost, err
}
// NeedsRehash 检查密码是否需要重新哈希(当前成本低于推荐成本时)
// hashedPassword: 密码哈希值
// preferredCost: 推荐的加密成本
// 返回是否需要重新哈希
func NeedsRehash(hashedPassword string, preferredCost int) (bool, error) {
currentCost, err := GetCost(hashedPassword)
if err != nil {
return false, err
}
return currentCost < preferredCost, nil
}