121 lines
2.8 KiB
Go
121 lines
2.8 KiB
Go
package util
|
||
|
||
import (
|
||
"crypto/rand"
|
||
"crypto/sha256"
|
||
"encoding/base64"
|
||
"fmt"
|
||
"strings"
|
||
"time"
|
||
|
||
"golang.org/x/crypto/bcrypt"
|
||
)
|
||
|
||
// HashPassword 使用bcrypt加密密码
|
||
func HashPassword(password string) (string, error) {
|
||
bytes, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||
if err != nil {
|
||
return "", fmt.Errorf("failed to hash password: %w", err)
|
||
}
|
||
return string(bytes), nil
|
||
}
|
||
|
||
// CheckPassword 验证密码
|
||
func CheckPassword(password, hash string) bool {
|
||
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
|
||
return err == nil
|
||
}
|
||
|
||
// GenerateRandomString 生成随机字符串
|
||
func GenerateRandomString(n int) (string, error) {
|
||
b := make([]byte, n)
|
||
_, err := rand.Read(b)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
return base64.URLEncoding.EncodeToString(b)[:n], nil
|
||
}
|
||
|
||
// GenerateVerificationToken 生成验证令牌
|
||
func GenerateVerificationToken() (string, error) {
|
||
return GenerateRandomString(32)
|
||
}
|
||
|
||
// GeneratePasswordResetToken 生成密码重置令牌
|
||
func GeneratePasswordResetToken() (string, error) {
|
||
token, err := GenerateRandomString(32)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
// 添加时间戳防止重复
|
||
return fmt.Sprintf("%s_%d", token, time.Now().Unix()), nil
|
||
}
|
||
|
||
// NormalizePhone 标准化手机号格式
|
||
func NormalizePhone(phone string) string {
|
||
// 移除所有非数字字符
|
||
phone = strings.Map(func(r rune) rune {
|
||
if r >= '0' && r <= '9' {
|
||
return r
|
||
}
|
||
return -1
|
||
}, phone)
|
||
|
||
// 如果以0开头,去掉0
|
||
if strings.HasPrefix(phone, "0") {
|
||
phone = phone[1:]
|
||
}
|
||
|
||
// 如果以86开头,去掉86
|
||
if strings.HasPrefix(phone, "86") {
|
||
phone = phone[2:]
|
||
}
|
||
|
||
return phone
|
||
}
|
||
|
||
// ValidatePasswordStrength 验证密码强度
|
||
func ValidatePasswordStrength(password string) error {
|
||
if len(password) < 8 {
|
||
return fmt.Errorf("password must be at least 8 characters long")
|
||
}
|
||
|
||
var hasUpper, hasLower, hasDigit bool
|
||
for _, char := range password {
|
||
switch {
|
||
case 'A' <= char && char <= 'Z':
|
||
hasUpper = true
|
||
case 'a' <= char && char <= 'z':
|
||
hasLower = true
|
||
case '0' <= char && char <= '9':
|
||
hasDigit = true
|
||
case strings.ContainsRune("!@#$%^&*()-_=+[]{}|;:,.<>?", char):
|
||
_ = true
|
||
}
|
||
}
|
||
|
||
// 至少包含大小写字母和数字
|
||
if !hasUpper || !hasLower || !hasDigit {
|
||
return fmt.Errorf("password must contain uppercase letters, lowercase letters and numbers")
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// GenerateSalt 生成盐值(如果需要自定义加密算法)
|
||
func GenerateSalt() (string, error) {
|
||
salt := make([]byte, 16)
|
||
_, err := rand.Read(salt)
|
||
if err != nil {
|
||
return "", err
|
||
}
|
||
return base64.StdEncoding.EncodeToString(salt), nil
|
||
}
|
||
|
||
// HashPasswordWithSalt 使用盐值哈希密码
|
||
func HashPasswordWithSalt(password, salt string) string {
|
||
hash := sha256.New()
|
||
hash.Write([]byte(password + salt))
|
||
return fmt.Sprintf("%x", hash.Sum(nil))
|
||
}
|