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
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
|
|
}
|
|
|