226 lines
6.5 KiB
Go
226 lines
6.5 KiB
Go
package validator
|
||
|
||
import (
|
||
"errors"
|
||
"fmt"
|
||
"regexp"
|
||
"strconv"
|
||
"strings"
|
||
"time"
|
||
|
||
"github.com/go-playground/validator/v10"
|
||
)
|
||
|
||
var validate *validator.Validate
|
||
|
||
// 初始化自定义校验器
|
||
func init() {
|
||
validate = validator.New()
|
||
|
||
if err := validate.RegisterValidation("name", validName); err != nil {
|
||
panic(fmt.Sprintf("注册 name 验证器时发生错误: %v", err))
|
||
}
|
||
|
||
// 注册自定义验证器 validmobile
|
||
if err := validate.RegisterValidation("mobile", validmobile); err != nil {
|
||
panic(fmt.Sprintf("注册 mobile 验证器时发生错误: %v", err))
|
||
}
|
||
|
||
// 注册自定义验证器 validDate
|
||
if err := validate.RegisterValidation("date", validDate); err != nil {
|
||
panic(fmt.Sprintf("注册 date 验证器时发生错误: %v", err))
|
||
}
|
||
|
||
// 注册自定义验证器 validIDCard
|
||
if err := validate.RegisterValidation("idCard", validIDCard); err != nil {
|
||
panic(fmt.Sprintf("注册 idCard 验证器时发生错误: %v", err))
|
||
}
|
||
|
||
if err := validate.RegisterValidation("bankCard", validBankCard); err != nil {
|
||
panic(fmt.Sprintf("注册 bankCard 验证器时发生错误: %v", err))
|
||
}
|
||
|
||
if err := validate.RegisterValidation("USCI", validUSCI); err != nil {
|
||
panic(fmt.Sprintf("注册 USCI 社会统一信用代码 验证器时发生错误: %v", err))
|
||
}
|
||
|
||
if err := validate.RegisterValidation("mobileType", validMobileType); err != nil {
|
||
panic(fmt.Sprintf("注册 mobileType 验证器时发生错误: %v", err))
|
||
}
|
||
if err := validate.RegisterValidation("password", validatePassword); err != nil {
|
||
panic(fmt.Sprintf("注册 password 验证器时发生错误: %v", err))
|
||
}
|
||
if err := validate.RegisterValidation("payMethod", validatePayMethod); err != nil {
|
||
panic(fmt.Sprintf("注册 payMethod 验证器时发生错误: %v", err))
|
||
}
|
||
|
||
}
|
||
|
||
// 弱口令列表
|
||
var weakPasswords = []string{
|
||
"12345678", "password", "123456789", "qwerty", "123456", "letmein",
|
||
"1234567", "welcome", "abc123", "password1", "1234", "111111", "admin",
|
||
}
|
||
|
||
// Validate 校验参数逻辑
|
||
func Validate(req interface{}) error {
|
||
if err := validate.Struct(req); err != nil {
|
||
// 检查 err 是否是 ValidationErrors 类型
|
||
if validationErrors, ok := err.(validator.ValidationErrors); ok {
|
||
for _, validationErr := range validationErrors {
|
||
field := validationErr.StructField()
|
||
tag := validationErr.Tag()
|
||
return errors.New(GetErrorMessage(field, tag))
|
||
}
|
||
} else {
|
||
// 其他错误处理
|
||
return fmt.Errorf("验证时出现未知错误: %v", err)
|
||
}
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// 自定义的名称验证
|
||
func validName(fl validator.FieldLevel) bool {
|
||
name := fl.Field().String()
|
||
validNamePattern := `^[\p{Han}]+$`
|
||
matched, _ := regexp.MatchString(validNamePattern, name)
|
||
return matched
|
||
}
|
||
|
||
// 自定义的手机号验证
|
||
func validmobile(fl validator.FieldLevel) bool {
|
||
phone := fl.Field().String()
|
||
validmobilePattern := `^1[3-9]\d{9}$`
|
||
matched, _ := regexp.MatchString(validmobilePattern, phone)
|
||
return matched
|
||
}
|
||
|
||
// 自定义正则表达式校验 yyyyMMdd 格式
|
||
func validDate(fl validator.FieldLevel) bool {
|
||
date := fl.Field().String()
|
||
validDatePattern := `^\d{4}(0[1-9]|1[0-2])(0[1-9]|[12][0-9]|3[01])$`
|
||
matched, _ := regexp.MatchString(validDatePattern, date)
|
||
return matched
|
||
}
|
||
|
||
|
||
// 自定义身份证校验(增强版)
|
||
// 校验规则:
|
||
// 1. 格式:18位,前6位地区码(首位不为0),7-14位出生日期,15-17位顺序码,18位校验码
|
||
// 2. 出生日期必须合法(验证年月日有效性,包括闰年)
|
||
// 3. 校验码按照GB 11643-1999标准计算验证
|
||
func validIDCard(fl validator.FieldLevel) bool {
|
||
idCard := fl.Field().String()
|
||
|
||
// 1. 基本格式验证:地区码(6位) + 年(4位) + 月(2位) + 日(2位) + 顺序码(3位) + 校验码(1位)
|
||
validIDPattern := `^[1-9]\d{5}(18|19|20)\d{2}((0[1-9])|(1[0-2]))(([0-2][1-9])|10|20|30|31)\d{3}[\dXx]$`
|
||
matched, _ := regexp.MatchString(validIDPattern, idCard)
|
||
if !matched {
|
||
return false
|
||
}
|
||
|
||
// 2. 验证出生日期的合法性
|
||
year, _ := strconv.Atoi(idCard[6:10])
|
||
month, _ := strconv.Atoi(idCard[10:12])
|
||
day, _ := strconv.Atoi(idCard[12:14])
|
||
|
||
// 构造日期并验证是否合法(time包会自动处理闰年等情况)
|
||
birthDate := time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.UTC)
|
||
if birthDate.Year() != year || int(birthDate.Month()) != month || birthDate.Day() != day {
|
||
return false // 日期不合法,如2月30日、4月31日等
|
||
}
|
||
|
||
// 3. 验证校验码(按照GB 11643-1999标准)
|
||
return validateIDCardChecksum(idCard)
|
||
}
|
||
|
||
// 验证身份证校验码(GB 11643-1999标准)
|
||
func validateIDCardChecksum(idCard string) bool {
|
||
// 加权因子
|
||
weights := []int{7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2}
|
||
// 校验码对应值
|
||
checksumChars := []byte{'1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'}
|
||
|
||
sum := 0
|
||
for i := 0; i < 17; i++ {
|
||
num := int(idCard[i] - '0')
|
||
sum += num * weights[i]
|
||
}
|
||
|
||
// 计算校验码
|
||
checksum := checksumChars[sum%11]
|
||
lastChar := idCard[17]
|
||
|
||
// 支持小写x
|
||
if lastChar == 'x' {
|
||
lastChar = 'X'
|
||
}
|
||
|
||
return byte(lastChar) == checksum
|
||
}
|
||
|
||
func validBankCard(fl validator.FieldLevel) bool {
|
||
bankCard := fl.Field().String()
|
||
// 银行卡号一般是13到19位的数字
|
||
validBankCardPattern := `^\d{13,19}$`
|
||
matched, _ := regexp.MatchString(validBankCardPattern, bankCard)
|
||
return matched
|
||
}
|
||
|
||
func validUSCI(fl validator.FieldLevel) bool {
|
||
usci := fl.Field().String()
|
||
// 社会信用代码为18位数字和大写字母的组合,最后一位为校验码
|
||
validUSCIPattern := `^[1-9A-Z]{2}[0-9]{6}[0-9A-Z]{9}[0-9A-Z]$`
|
||
matched, _ := regexp.MatchString(validUSCIPattern, usci)
|
||
return matched
|
||
}
|
||
|
||
// 自定义的手机号类型验证(可以为空)
|
||
func validMobileType(fl validator.FieldLevel) bool {
|
||
mobileType := fl.Field().String()
|
||
if mobileType == "" {
|
||
return true // 如果为空,认为是有效的
|
||
}
|
||
|
||
// 校验是否是 CTCC, CMCC, CUCC 之一
|
||
validTypes := map[string]bool{
|
||
"CTCC": true, // 中国电信
|
||
"CMCC": true, // 中国移动
|
||
"CUCC": true, // 中国联通
|
||
}
|
||
|
||
return validTypes[mobileType]
|
||
}
|
||
|
||
// 自定义密码强度校验函数
|
||
func validatePassword(fl validator.FieldLevel) bool {
|
||
password := fl.Field().String()
|
||
|
||
// 检查密码是否在弱口令列表中
|
||
for _, weakPwd := range weakPasswords {
|
||
if strings.ToLower(password) == weakPwd {
|
||
return false
|
||
}
|
||
}
|
||
|
||
return true
|
||
}
|
||
|
||
// 支付方式
|
||
func validatePayMethod(fl validator.FieldLevel) bool {
|
||
payMethod := fl.Field().String()
|
||
|
||
if payMethod == "" {
|
||
return true // 如果为空,认为是有效的
|
||
}
|
||
|
||
validTypes := map[string]bool{
|
||
"alipay": true, // 中国电信
|
||
"wechatpay": true, // 中国移动
|
||
}
|
||
|
||
return validTypes[payMethod]
|
||
|
||
}
|