61 lines
1.3 KiB
Go
61 lines
1.3 KiB
Go
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
|
|
}
|