作为后端开发者我们要记住一句话:“永远不要相信用户的输入”,这里所说的用户可能是人,也可能是另一个应用程序。“永远不要相信用户的输入”是安全编码的准则,也就是说,任何输入的内容在验证无害之前都是有害的。很多应用程序的安全漏洞都和用户输入有关,比如SQL注入漏洞。

验证非必填的邮箱字段

需求是这样的:我们需要验证一个字段可以为空,同时字段的值为合法的电子邮箱。

type MailRequest struct {
	Email    string `json:"email" binding:"email"` // 邮箱地址
}
requiredEmail必须是一个有效的邮箱omitemptyomitemptyomitempty
type MailRequest struct {
	Email    string `json:"email" binding:"omitempty,email"` // 邮箱地址
}

验证0值

先看代码

type AddRoleRequest struct {
	Available int `json:"available" binding:"required"` // 是否可用 0 不可用 1 可用
}
AvailableintrequiredAvailable*int
type AddRoleRequest struct {
	Available *int `json:"available" binding:"required"` // 是否可用 0 不可用 1 可用
}

自定义错误消息

前文基于gin的golang web开发:模型验证结尾部分,我们没有把参数验证的错误消息完全翻译成中文,字段名还是英文的。显然还有更优雅的做法,给用户提示一个更友好的错误信息。

{
    "error": "Username为必填字段;"
}
Username
func init() {
	translator := zh.New()
	uni = ut.New(translator, translator)
	trans, _ = uni.GetTranslator("zh")
	validate := binding.Validator.Engine().(*validator.Validate)
	// 注意这里
	validate.RegisterTagNameFunc(func(fld reflect.StructField) string {
		return fld.Tag.Get("display")
	})
	_ = zh_translations.RegisterDefaultTranslations(validate, trans)
}

func Translate(err error) string {
	var result string

	errors := err.(validator.ValidationErrors)

	for _, err := range errors {
		errMessage := err.Translate(trans)
		result += errMessage + ";"
	}
	return result[:len(result)-1] // 
validate.RegisterTagNameFuncdisplayTranslate

举个栗子

func checkUser(user string, password string) bool {
	db := GetDbContext()
	defer db.Close()

	dataSql := `
select count(1) from sys_user
where username = '` + user + `' and password = '` + password + `'`
	count := 0
	log.Println(dataSql)
	db.QueryRow(dataSql).Scan(&count)
	return count > 0
}
1' or '1'='1dataSql
select count(1) from sys_user
where username = 'xxx' and password = '1' or '1'='1'
passwordalphanum1' or '1'='1
type UserAndPassword struct {
	User string `json:"user" binding:"required,alphanum"`
	Pwd  string `json:"pwd" binding:"required,alphanum"`
}

func IsLoginIn(c *gin.Context) {
	var req = UserAndPassword{}
	if err := c.ShouldBindJSON(&req); err != nil {
		c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
		return
	}

	c.String(http.StatusOK, strconv.FormatBool(checkUser(req.User, req.Pwd)))
}

func checkUser(user string, password string) bool {
	db := GetDbContext()
	defer db.Close()

	dataSql := `
select count(1) from sys_user
where username = '` + user + `' and password = '` + password + `'`
	count := 0
	log.Println(dataSql)
	db.QueryRow(dataSql).Scan(&count)
	return count > 0
}