package security import ( "fmt" "unicode" "unicode/utf8" ) // PasswordPolicy defines the runtime password rules enforced by services. type PasswordPolicy struct { MinLength int RequireSpecial bool RequireNumber bool } // Normalize fills in safe defaults for unset policy fields. func (p PasswordPolicy) Normalize() PasswordPolicy { if p.MinLength <= 0 { p.MinLength = 8 } return p } // Validate checks whether the password satisfies the configured policy. func (p PasswordPolicy) Validate(password string) error { p = p.Normalize() if utf8.RuneCountInString(password) < p.MinLength { return fmt.Errorf("密码长度不能少于%d位", p.MinLength) } var hasUpper, hasLower, hasNumber, hasSpecial bool for _, ch := range password { switch { case unicode.IsUpper(ch): hasUpper = true case unicode.IsLower(ch): hasLower = true case unicode.IsDigit(ch): hasNumber = true case unicode.IsPunct(ch) || unicode.IsSymbol(ch): hasSpecial = true } } if !hasUpper { return fmt.Errorf("密码必须包含大写字母") } if !hasLower { return fmt.Errorf("密码必须包含小写字母") } if p.RequireNumber && !hasNumber { return fmt.Errorf("密码必须包含数字") } if p.RequireSpecial && !hasSpecial { return fmt.Errorf("密码必须包含特殊字符") } return nil }