golang常用库之字段参数验证库-validator使用详解

golang常用库:gorilla/mux-http路由库使用
golang常用库:配置文件解析库-viper使用
golang常用库:操作数据库的orm框架-gorm基本使用
golang常用库:字段参数验证库-validator使用

一、背景

在平常开发中,特别是在web应用开发中,为了验证输入字段的合法性,都会做一些验证操作。比如对用户提交的表单字段进行验证,或者对请求的API接口字段进行验证,验证字段的合法性,保证输入字段值的安全,防止用户的恶意请求。

一般的做法是用正则表达式,一个字段一个字段的进行验证。一个一个字段验证的话,写起来比较繁琐。那有没更好的方法,进行字段的合法性验证?有, 这就是下面要介绍的 validator 这个验证组件。

代码地址:
https://github.com/go-playground/validator

文档地址:
https://github.com/go-playground/validator/blob/master/README.md

二、功能介绍

这个验证包 github.com/go-playground/validator 验证功能非常多。

标记之间特殊符号说明

  • 逗号( , ):把多个验证标记隔开。注意:隔开逗号之间不能有空格, validate:"lt=0,gt=100",逗号那里不能有空格,否则panic
  • 横线( - ):跳过该字段不验证
  • 竖线( | ):使用多个验证标记,但是只需满足其中一个即可
  • required:表示该字段值必输设置,且不能为默认值
  • omitempty:如果字段未设置,则忽略它

范围比较验证

doc: https://github.com/go-playground/validator/blob/master/README.md#comparisons

范围验证: 切片、数组和map、字符串,验证其长度;数值,验证大小范围

  • lte:小于等于参数值,validate:"lte=3" (小于等于3)
  • gte:大于等于参数值,validate:"lte=0,gte=120" (大于等于0小于等于120)
  • lt:小于参数值,validate:"lt=3" (小于3)
  • gt:大于参数值,validate:"lt=0,gt=120" (大于0小于120)
  • len:等于参数值,validate:"len=2"
  • max:大于等于参数值,validate:"max=2" (大于等于2)
  • min:小于等于参数值,validate:"min=2,max=10" (大于等于2小于等于10)
  • ne:不等于,validate:"ne=2" (不等于2)
  • oneof:只能是列举出的值其中一个,这些值必须是数值或字符串,以空格分隔,如果字符串中有空格,将字符串用单引号包围,validate:"oneof=red green"

例子:

type User struct {
  Name string `json:"name" validate:"min=0,max=35"`
  Age unit8 `json:"age" validate:"lte=0,gte=90"`
}

更多功能请参看文档 validator comparisons doc

字符串验证

doc: https://github.com/go-playground/validator/blob/master/README.md#strings

  • contains:包含参数子串,validate:"contains=tom" (字段的字符串值包含tom)
  • excludes:包含参数子串,validate:"excludes=tom" (字段的字符串值不包含tom)
  • startswith:以参数子串为前缀,validate:"startswith=golang"
  • endswith:以参数子串为后缀,validate:"startswith=world"

例子:

type User struct {
  Name string `validate:"contains=tom"`
  Age int `validate:"min=1"`
}

更多功能请参看文档 validator strings doc

字段验证

doc: https://github.com/go-playground/validator/blob/master/README.md#fields

eqcsfield:跨不同结构体字段验证,比如说 Struct1 Filed1,与结构体Struct2 Field2相等,

type Struct1 struct {
  Field1 string `validate:eqcsfield=Struct2.Field2`
  Struct2 struct {
    Field2 string
  }
}
  • necsfield:跨不同结构体字段不相等
  • eqfield:同一结构体字段验证相等,最常见的就是输入2次密码验证
type User struct {
  Name string `validate:"lte=4"`
  Age int `validate:"min=20"`
  Password string `validate:"min=10"`
  Password2 string `validate:"eqfield=Password"`
}

nefield:同一结构体字段验证不相等

type User struct {
  Name string `validate:"lte=4"`
  Age int `validate:"min=20"`
  Password string `validate:"min=10,nefield=Name"`
}
  • gtefield:大于等于同一结构体字段,validate:"gtefiled=Field2"
  • ltefield:小于等于同一结构体字段

更多功能请参看文档:validator Fields DOC

网络验证

doc: https://github.com/go-playground/validator/blob/master/README.md#network

  • ip:字段值是否包含有效的IP地址,validate:"ip"
  • ipv4:字段值是否包含有效的ipv4地址,validate:"ipv4"
  • ipv6:字段值是否包含有效的ipv6地址,validate:"ipv6"
  • uri:字段值是否包含有效的uri,validate:"uri"
  • url:字段值是否包含有效的uri,validate:"url"

更多功能请参看文档:validator network DOC

Format

doc: https://github.com/go-playground/validator/blob/master/README.md#format

base64:字段值是否包含有效的base64值

更多功能请参看文档 validator strings doc

其他

请参看文档: https://github.com/go-playground/validator/blob/master/README.md#other

三、安装

go get:

go get github.com/go-playground/validator/v10

在文件中引用validator包:

import "github.com/go-playground/validator/v10"

四、validator使用

文档:https://github.com/go-playground/validator/blob/master/README.md#examples

例子1:验证单个字段变量值

validation1.go

package main

import (
	"fmt"

	"github.com/go-playground/validator/v10"
)

func main() {
	validate := validator.New()

	var boolTest bool
	err := validate.Var(boolTest, "required")
	if err != nil {
		fmt.Println(err)
	}
	var stringTest string = ""
	err = validate.Var(stringTest, "required")
	if err != nil {
		fmt.Println(err)
	}

	var emailTest string = "test@126.com"
	err = validate.Var(emailTest, "email")
	if err != nil {
		fmt.Println(err)
	} else {
		fmt.Println("success") // 输出: success。 说明验证成功
	}

	emailTest2 := "test.126.com"
	errs := validate.Var(emailTest2, "required,email")
	if errs != nil {
		fmt.Println(errs) // 输出: Key: "" Error:Field validation for "" failed on the "email" tag。验证失败
	}

	fmt.Println("\r\nEnd!!")

}

运行输出:

go run simple1.go
Key: '' Error:Field validation for '' failed on the 'required' tag
Key: '' Error:Field validation for '' failed on the 'required' tag
success
Key: '' Error:Field validation for '' failed on the 'email' tag

End!!

例子2:验证结构体struct

from:struct validate

validation_struct.go,这个程序还列出了效验出错字段的一些信息,

package main

import (
	"fmt"

	"github.com/go-playground/validator/v10"
)

type User struct {
	FirstName string   `validate:"required"`
	LastName string   `validate:"required"`
	Age    uint8   `validate:"gte=0,lte=130"`
	Email   string   `validate:"required,email"`
	Addresses []*Address `validate:"required,dive,required"`
}

type Address struct {
	Street string `validate:"required"`
	City  string `validate:"required"`
	Planet string `validate:"required"`
	Phone string `validate:"required"`
}

func main() {
	address := &Address{
		Street: "Eavesdown Docks",
		Planet: "Persphone",
		Phone: "none",
	}

	user := &User{
		FirstName: "Badger",
		LastName: "Smith",
		Age:    135,
		Email:   "Badger.Smith@gmail.com",
		Addresses: []*Address{address},
	}

	validate := validator.New()
	err := validate.Struct(user)
	if err != nil {
		fmt.Println("=== error msg ====")
		fmt.Println(err)

		if _, ok := err.(*validator.InvalidValidationError); ok {
			fmt.Println(err)
			return
		}

		fmt.Println("\r\n=========== error field info ====================")
		for _, err := range err.(validator.ValidationErrors) {
      // 列出效验出错字段的信息
			fmt.Println("Namespace: ", err.Namespace())
			fmt.Println("Fild: ", err.Field())
			fmt.Println("StructNamespace: ", err.StructNamespace())
			fmt.Println("StructField: ", err.StructField())
			fmt.Println("Tag: ", err.Tag())
			fmt.Println("ActualTag: ", err.ActualTag())
			fmt.Println("Kind: ", err.Kind())
			fmt.Println("Type: ", err.Type())
			fmt.Println("Value: ", err.Value())
			fmt.Println("Param: ", err.Param())
			fmt.Println()
		}

		// from here you can create your own error messages in whatever language you wish
		return
	}
}

运行 输出:

$ go run validation_struct.go
=== error msg ====
Key: 'User.Age' Error:Field validation for 'Age' failed on the 'lte' tag
Key: 'User.Addresses[0].City' Error:Field validation for 'City' failed on the 'required' tag

=========== error field info ====================
Namespace: User.Age
Fild: Age
StructNamespace: User.Age
StructField: Age
Tag: lte
ActualTag: lte
Kind: uint8
Type: uint8
Value: 135
Param: 130

Namespace: User.Addresses[0].City
Fild: City
StructNamespace: User.Addresses[0].City
StructField: City
Tag: required
ActualTag: required
Kind: string
Type: string
Value:
Param:

还可以给字段加一些其他tag信息,方面form,json的解析,如下:

type User struct {
  FirstName string   `form:"firstname" json:"firstname" validate:"required"`
	LastName string   `form:"lastname" json:"lastname" validate:"required"`
	Age    uint8   ` form:"age" json:"age"validate:"gte=0,lte=130"`
	Email   string   ` form:"email" json:"email" validate:"required,email"`
}

用户自定义函数验证

用户自定义函数验证字段是否合法,效验是否正确。

例子3: 通过字段tag自定义函数

validate.RegisterValidation

customer_tag.go:

package main

import (
	"fmt"

	"github.com/go-playground/validator/v10"
)

type User struct {
	Name string `form:"name" json:"name" validate:"required,CustomerValidation"` //注意:required和CustomerValidation之间不能有空格,否则panic。CustomerValidation:自定义tag-函数标签
	Age uint8 ` form:"age" json:"age" validate:"gte=0,lte=80"`         //注意:gte=0和lte=80之间不能有空格,否则panic
}

var validate *validator.Validate

func main() {
	validate = validator.New()
	validate.RegisterValidation("CustomerValidation", CustomerValidationFunc) //注册自定义函数,前一个参数是struct里tag自定义,后一个参数是自定义的函数

	user := &User{
		Name: "jimmy",
		Age: 86,
	}

	fmt.Println("first value: ", user)
	err := validate.Struct(user)
	if err != nil {
		fmt.Printf("Err(s):\n%+v\n", err)
	}

	user.Name = "tom"
	user.Age = 29
	fmt.Println("second value: ", user)
	err = validate.Struct(user)
	if err != nil {
		fmt.Printf("Err(s):\n%+v\n", err)
	}
}

// 自定义函数
func CustomerValidationFunc(f1 validator.FieldLevel) bool {
  // f1 包含了字段相关信息
  // f1.Field() 获取当前字段信息
  // f1.Param() 获取tag对应的参数
  // f1.FieldName() 获取字段名称

	return f1.Field().String() == "jimmy"
}

运行输出:

$ go run customer.go
first value: &{jimmy 86}
Err(s):
Key: 'User.Age' Error:Field validation for 'Age' failed on the 'lte' tag
second value: &{tom 29}
Err(s):
Key: 'User.Name' Error:Field validation for 'Name' failed on the 'CustomerValidation' tag

**注意

上面代码user struct定义中 ,validate里的required和CustomerValidation之间不能有空格,否则运行时报panic错误:panic: Undefined validation function ' CustomerValidation' on field 'Name'

例子4:自定义函数-直接注册函数1

不通过字段tag自定义函数,直接注册函数。

RegisterStructValidation

https://github.com/go-playground/validator/blob/master/_examples/struct-level/main.go

customer1.go

package main

import (
	"fmt"

	"github.com/go-playground/validator/v10"
)

type User struct {
	FirstName   string `json:firstname`
	LastName    string `json:lastname`
	Age      uint8 `validate:"gte=0,lte=130"`
	Email     string `validate:"required,email"`
	FavouriteColor string `validate:"hexcolor|rgb|rgba"`
}

var validate *validator.Validate

func main() {
	validate = validator.New()

	validate.RegisterStructValidation(UserStructLevelValidation, User{})

	user := &User{
		FirstName:   "",
		LastName:    "",
		Age:      30,
		Email:     "TestFunc@126.com",
		FavouriteColor: "#000",
	}

	err := validate.Struct(user)
	if err != nil {
		fmt.Println(err)
	}
}

func UserStructLevelValidation(sl validator.StructLevel) {
	user := sl.Current().Interface().(User)

	if len(user.FirstName) == 0 && len(user.LastName) == 0 {
		sl.ReportError(user.FirstName, "FirstName", "firstname", "firstname", "")
		sl.ReportError(user.LastName, "LastName", "lastname", "lastname", "")
	}
}

运行输出:

$ go run customer1.go
Key: 'User.FirstName' Error:Field validation for 'FirstName' failed on the 'firstname' tag
Key: 'User.LastName' Error:Field validation for 'LastName' failed on the 'lastname' tag

例子5:自定义函数-直接注册函数2

RegisterCustomTypeFunc

https://github.com/go-playground/validator/blob/master/_examples/custom/main.go

validate.RegisterCustomTypeFunc:验证类型的自定义函数

customer2.go:

package main

import (
	"database/sql"
	"database/sql/driver"
	"fmt"
	"reflect"

	"github.com/go-playground/validator/v10"
)

type DbBackedUser struct {
	Name sql.NullString `validate:"required"`
	Age sql.NullInt64 `validate:"required"`
}

var validate *validator.Validate

func main() {
	validate = validator.New()

	validate.RegisterCustomTypeFunc(ValidateValuer, sql.NullString{}, sql.NullInt64{}, sql.NullBool{}, sql.NullFloat64{})

	// build object for validation
	x := DbBackedUser{Name: sql.NullString{String: "", Valid: true}, Age: sql.NullInt64{Int64: 0, Valid: false}}

	err := validate.Struct(x)
	if err != nil {
		fmt.Printf("Err(s):\n%+v\n", err)
	}
}

func ValidateValuer(field reflect.Value) interface{} {
	if valuer, ok := field.Interface().(driver.Valuer); ok {
		val, err := valuer.Value()
		if err == nil {
			return val
		}
		// handle the error how you want
	}
	return nil
}

运行输出:

$ go run customer.go
Err(s):
Key: 'DbBackedUser.Name' Error:Field validation for 'Name' failed on the 'required' tag
Key: 'DbBackedUser.Age' Error:Field validation for 'Age' failed on the 'required' tag

注意,这个函数
RegisterCustomTypeFunc,它上面有2行注释:

// RegisterCustomTypeFunc registers a CustomTypeFunc against a number of types
//
// NOTE: this method is not thread-safe it is intended that these all be registered prior to any validation

它是一个验证数据类型自定义函数,NOTE:这个方法不是线程安全的

五、参考https://github.com/go-playground/validator/blob/master/README.mdhttps://github.com/go-playground/validator/tree/master/_examples

总结

到此这篇关于golang常用库:字段参数验证库-validator使用的文章就介绍到这了,更多相关golang字段参数验证库validator内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

时间: 2020-10-15

简单解析Django框架中的表单验证

我们的搜索示例仍然相当地简单,特别从数据验证方面来讲:我们仅仅只验证搜索关键值是否为空. 然后许多HTML表单包含着比检测值是否为空更为复杂的验证. 我们都有在网站上见过类似以下的错误提示信息: 请输入一个有效的email地址, foo' 并不是一个有效的e-mail地址. 请输入5位数的U.S 邮政编码, 123并非是一个有效的邮政编码. 请输入YYYY-MM-DD格式的日期. 请输入8位数以上并至少包含一个数字的密码. 关于JavaScript验证 可以使用Javascript在客户端浏览器

python django集成cas验证系统

加入cas的好处 cas是什么东西就不多说了,简而言之就是单点登陆系统,一处登陆,全网有权限的系统均可以访问. 一次登陆,多个系统互通 cas一般均放置在内网,加入cas验证则必须要求用户走vpn访问,提高安全性; cas可和域控等系统结合,密码定时过期; 基本认证统一走cas控制,减去开帐号等麻烦事; django 如何使用cas验证 django 的好处就是支持的包多,网上已经有大神做好的相关的app,直接下载.安装就可以了. 我们要做的就是下载.解压拷贝,略微配置下就可以跑了. 至于安装也

Mongodb常用的身份验证方式

1. 介绍 不管数据库是在多安全的环境或者本地环境,给数据库建立一个安全的环境是很有必要的. Mongodb提供了一系列的 安全功能 ,这里介绍一种很常用的身份验证方式. 2. 开启验证 默认情况下,只要在启动数据库的时候没有加上 --auth 选项,就是没有身份验证功能的,所有客户端都可以进行所有权限的操作. 如果加上过后,我们就可以通过安全的身份验证连接数据库.如果要在数据库中进行身份验证,可以通过 db.auth(username, password) ,如果验证成功则返回1,反之. 3.

java使用google身份验证器实现动态口令验证的示例

最近有用户反应我们现有的短信+邮件验证,不安全及短信条数限制和邮件收验证码比较慢的问题,希望我们也能做一个类似银行动态口令的验证方式.经过对可行性的分析及慎重考虑,可以实现一个这样的功能. 怎么实现呢,是自己开发一个这样的app?这样成本太高了,为了节约成本,我们使用互联网使用比较多的google身份验证器.使用它,我们只需要开发服务端就可以了. google身份验证器的原理是什么呢?客户端和服务器事先协商好一个密钥K,用于一次性密码的生成过程,此密钥不被任何第三方所知道.此外,客户端和服务器各

Java使用OTP动态口令(每分钟变一次)进行登录认证

GIT地址:https://github.com/suyin58/otp-demo 动态码截图: 在对外网开放的后台管理系统中,使用静态口令进行身份验证可能会存在如下问题: (1) 为了便于记忆,用户多选择有特征作为密码,所有静态口令相比动态口令而言,容易被猜测和破解: (2) 黑客可以从网上或电话线上截获静态密码,如果是非加密方式传输,用户认证信息可被轻易获取: (3) 内部工作人员可通过合法授权取得用户密码而非法使用: 静态口令根本上不能确定用户的身份,其结果是,个人可以轻松地伪造一个假身份

Angular2表单自定义验证器的实现

本文主要给大家介绍如何判断验证器的结果.在这里,我们就来看看怎样实现一个自定义的验证器. 目标 我们要实现一个验证手机号的验证器,使用的实例还是基于之前的文章里面的实例,也就是用户信息输入的表单页面.我们在手机号的元素上添加一个验证手机号的验证器.然后,如果手机号验证失败,就显示一个错误,页面如下: 这部分教程的代码可以从github获取: git clone https://github.com/Mavlarn/angular2-forms-tutorial 如果要运行,进入项目目录,运行下面

Python装饰器使用实例:验证参数合法性

python是不带静态检查的动态语言,有时候需要在调用函数时保证参数合法.检查参数合法性是一个显著的切面场景,各个函数都可能有这个需求.但另一方面,参数合法性是不是应该由调用方来保证比较好也是一个需要结合实际才能回答的问题,总之双方约定好,不要都不检查或者都检查就可以了.下面这个模块用于在函数上使用装饰器进行参数的合法性验证. 你可以直接执行这个模块进行测试,如果完全没有输出则表示通过.你也可以找到几个以_test开头的函数,所有的测试用例都包含在这几个函数中.使用方法参见模块文档和测试用例.

详解vue-validator(vue验证器)

官方文档:http://vuejs.github.io/vue-validator/zh-cn/index.html github项目地址:https://github.com/vuejs/vue-validator 单独使用vue-validator的方法见官方文档,本文结合vue-router使用. 安装验证器 不添加自定义验证器或者无需全局使用的公用验证器,在main.js中安装验证器,使用 CommonJS 模块规范, 需要显式的使用 Vue.use() 安装验证器组件. import

Yii2验证器(Validator)用法分析

本文实例讲述了Yii2验证器(Validator)用法.分享给大家供大家参考,具体如下: 先看一下验证器的使用. public function rules() { return [ [['email', 'password'], 'required'], ['password', 'string', 'min'=>6], ]; } 如上所示,验证器主要使用在rules里面,对当前model里面的属性值进行验证以检查是否满足某种要求. 验证器使用格式: 书写格式为:[需要验证的属性,验证器名称,

Yii核心验证器api详解

本文实例讲述了Yii核心验证器api.分享给大家供大家参考,具体如下: 核心验证器 Core Validators 前言 Yii 提供了一系列常用的核心 validators, 你可在 yii\validators namespace 中找到. 不用使用长的验证器类名, 你可以使用别名代替他们. 例如, 你可以使用别名 required 代替 yii\validators\RequiredValidator 类: <?php public function rules() { return [

Java实现的自定义类加载器示例

本文实例讲述了Java实现的自定义类加载器.分享给大家供大家参考,具体如下: 一 点睛 1 ClassLoader类有如下两个关键方法: loadClass(String name, boolean resolve):该方法为ClassLoader的入口点,根据指定的二进制名称来加载类,系统就是调用ClassLoader的该方法来获取指定类对应的Class对象. findClass(String name):根据二进制名称来查找类. 如果需要实现自定义的ClassLoader,可以通过重写以上两

Socket+JDBC+IO实现Java文件上传下载器DEMO详解

该demo实现的功能有: 1.用户注册: 注册时输入两次密码,若两次输入不一致,则注册失败,需要重新输入.若用户名被注册过,则提示用户重新输入用户名: 2.用户登录: 需要验证数据库中是否有对应的用户名和密码,若密码输错三次,则终止用户的登录操作: 3.文件上传: 从本地上传文件到文件数据库中 4.文件下载: 从数据库中下载文件到本地 5.文件更新: 根据id可更新数据库中的文件名 6.文件删除: 根据id删除数据库中某一个文件 7.看数据库所有文件; 8.查看文件(根据用户名); 9.查看文件

Java动态编译执行代码示例

在某些情况下,我们需要动态生成java代码,通过动态编译,然后执行代码.JAVAAPI提供了相应的工具(JavaCompiler)来实现动态编译.下面我们通过一个简单的例子介绍,如何通过JavaCompiler实现java代码动态编译. 一.获取JavaCompiler JavaCompiler compiler = ToolProvider.getSystemJavaCompiler(); 获取JDK提供的java编译器,如果没有提供编译器,则返回null: 二.编译 //获取java文件管理