90 lines
2.5 KiB
Go
90 lines
2.5 KiB
Go
package validation
|
||
|
||
import (
|
||
"strconv"
|
||
"unicode"
|
||
)
|
||
|
||
// PasswordConfig 密码验证配置
|
||
type PasswordConfig struct {
|
||
MinLength int // 最小长度
|
||
MaxLength int // 最大长度
|
||
RequireUpper bool // 需要大写字母
|
||
RequireLower bool // 需要小写字母
|
||
RequireDigit bool // 需要数字
|
||
RequireSpecial bool // 需要特殊字符
|
||
}
|
||
|
||
// DefaultPasswordConfig 默认密码配置。
|
||
//
|
||
// P1 #17:MaxLength 由 128 收敛到 72(字节)。bcrypt 在 72 字节处静默截断——
|
||
// 若允许更长密码,两个前 72 字节相同的不同密码会被视为同一密码通过认证。
|
||
// length 用 len()(字节)度量,与 bcrypt 的字节截断口径一致。需支持超长密码时,
|
||
// 应在哈希前先做 SHA-256 预哈希再交给 bcrypt,而非放宽此上限。
|
||
var DefaultPasswordConfig = PasswordConfig{
|
||
MinLength: 8, // 最少8位
|
||
MaxLength: 72, // 最多72字节(bcrypt 截断边界,见上)
|
||
RequireUpper: true,
|
||
RequireLower: true,
|
||
RequireDigit: true,
|
||
RequireSpecial: false,
|
||
}
|
||
|
||
// ValidatePassword 验证密码强度
|
||
// 返回:是否有效,错误信息
|
||
func ValidatePassword(password string) (bool, string) {
|
||
return ValidatePasswordWithConfig(password, DefaultPasswordConfig)
|
||
}
|
||
|
||
// ValidatePasswordWithConfig 使用指定配置验证密码强度
|
||
func ValidatePasswordWithConfig(password string, config PasswordConfig) (bool, string) {
|
||
length := len(password)
|
||
|
||
// 检查最小长度
|
||
if length < config.MinLength {
|
||
return false, "密码长度不能少于" + strconv.Itoa(config.MinLength) + "位"
|
||
}
|
||
|
||
// 检查最大长度
|
||
if length > config.MaxLength {
|
||
return false, "密码长度不能超过" + strconv.Itoa(config.MaxLength) + "位"
|
||
}
|
||
|
||
var hasUpper, hasLower, hasDigit, hasSpecial bool
|
||
|
||
for _, char := range password {
|
||
switch {
|
||
case unicode.IsUpper(char):
|
||
hasUpper = true
|
||
case unicode.IsLower(char):
|
||
hasLower = true
|
||
case unicode.IsDigit(char):
|
||
hasDigit = true
|
||
case unicode.IsPunct(char) || unicode.IsSymbol(char):
|
||
hasSpecial = true
|
||
}
|
||
}
|
||
|
||
// 检查大写字母
|
||
if config.RequireUpper && !hasUpper {
|
||
return false, "密码必须包含大写字母"
|
||
}
|
||
|
||
// 检查小写字母
|
||
if config.RequireLower && !hasLower {
|
||
return false, "密码必须包含小写字母"
|
||
}
|
||
|
||
// 检查数字
|
||
if config.RequireDigit && !hasDigit {
|
||
return false, "密码必须包含数字"
|
||
}
|
||
|
||
// 检查特殊字符
|
||
if config.RequireSpecial && !hasSpecial {
|
||
return false, "密码必须包含特殊字符"
|
||
}
|
||
|
||
return true, ""
|
||
}
|