package CheckHandler import ( "dsSzxy/Utils/CommonUtil" "encoding/json" "fmt" "github.com/gin-gonic/gin" "io/ioutil" "log" "os" "strings" ) //检查器数组,注意位置,因为使用了数组的索引值!!!! var checkTagsArray = []string{ "x-lengthlimit", //0、长度检查器 "x-emptylimit", //1、非空检查器 "x-tellimit", //2、手机号检查器 "x-emaillimit", //3、邮箱检查器 "x-idcardlimit", //4、身份证号检查器 "x-datetime", //5、日期类型检查器 "x-intrangelimit", //6、整数长度检查器 "x-floatrangelimit", //7、浮点数长度检查器 "x-rolelimit", //8、数据权限检查器 } //转为map方便以O(1)进行命中,不用反复循环调用数组进行检查,可以理解为与上面的数组是同一个东西的两种形态 var checkTagsMap = make(map[string]int) //接口中的参数结构体 type parameterStruct struct { parameterName string //参数名称 paraRange string //参数范围 must bool //是不是必须,即swagger配置中的required inputParameterValue string //用户输入值 } //参数Map // key:interfaceName+"_"+httpType+"_"+checkType //如果需要检查,在每个具体的检查器实现中,检查器知道自己该检查哪个标签,直接以上面key的命名规则,三连击,找到这种检查的参数列表数组 var parameterMap = make(map[string][]parameterStruct, 0) //从swagger文件中读取需要的配置参数 func init() { //1、需要检查哪些标签关键字,初始化到map中,即数组--->Map,为了O(1) for i := 0; i < len(checkTagsArray); i++ { checkTagsMap[checkTagsArray[i]] = 1 } //2、读取swagger.json inter := readSwaggerJson() //3、初始化数据 m := inter.(map[string]interface{}) n := m["paths"].(map[string]interface{}) for k1, v1 := range n { t := v1.(map[string]interface{}) //默认是get,如果设置了post,那么修改为post var httpType = "get" if t["post"] != nil { httpType = "post" } //对于每一个接口,如果它配置了我们约定的检查器,需要记录下来 d := t[httpType].(map[string]interface{}) for k2, v2 := range d { _, ok := checkTagsMap[k2] //k2:我们自定义的扩展标签,比如:X-EmptyLimit if ok { //参数列表 paras := v2.([]interface{}) for i := 0; i < len(paras); i++ { //参数可以是一组,也可以是一个 switch paras[i].(type) { //一个 case string: //填充参数,k1:接口名称,httpType:访问类型 fillParameterMap(k1, httpType, k2, paras[i].(string), "", isRequired(d, paras[i].(string))) break //一组 case map[string]interface{}: for k3, v3 := range paras[i].(map[string]interface{}) { //填充参数 fillParameterMap(k1, httpType, k2, k3, v3.(string), isRequired(d, k3)) } break } } } } } } /** 功能:判断接口请求是不是合法 作者:黄海 时间:2020-03-16 */ func IsLegal(c *gin.Context) (bool, ResultStruct) { //纯接口名称,不要get后面的参数 jkName := strings.Split(c.Request.RequestURI, "?")[0] //0、长度检查 success, resultStruct := lengthLimitIsLegal(c, jkName, 0) if !success { return success, resultStruct } //1、非空检查 success, resultStruct = emptyLimitIsLegal(c, jkName, 1) if !success { return success, resultStruct } //2、手机号 success, resultStruct = telLimitIsLegal(c, jkName, 2) if !success { return success, resultStruct } //3、邮箱 success, resultStruct = emailLimitIsLegal(c, jkName, 3) if !success { return success, resultStruct } //4、身份证 success, resultStruct = idcardLimitIsLegal(c, jkName, 4) if !success { return success, resultStruct } //5、时间格式 success, resultStruct = datetimeLimitIsLegal(c, jkName, 5) if !success { return success, resultStruct } //6、整数范围检查 success, resultStruct = intRangeLimitIsLegal(c, jkName, 6) if !success { return success, resultStruct } //7、浮点数范围检查 success, resultStruct = floatRangeLimitIsLegal(c, jkName, 7) if !success { return success, resultStruct } return true, resultStruct } /** 功能:是不是必须填写项目 作者:黄海 时间:2020-05-22 */ func isRequired(d map[string]interface{}, parameterName string) bool { //此参数是否为必填写项 if d["parameters"] != nil { for _, v2 := range d["parameters"].([]interface{}) { c2 := v2.(map[string]interface{}) for k2, v2 := range c2 { if c2["name"] == parameterName { if k2 == "required" { return v2.(bool) //标识是否是必须项 } } } } } return false } /** 功能:填充参数map 作者:黄海 时间:2020-05-22 */ func fillParameterMap(interfaceName string, httpType string, checkType string, parameterName string, paraRange string, must bool) { var ps parameterStruct //参数名称 ps.parameterName = parameterName //参数范围 ps.paraRange = paraRange //没有参数范围限定 //参数是不是必需填写项目? ps.must = must //存入map parameterMap[interfaceName+"_"+httpType+"_"+checkType] = append(parameterMap[interfaceName+"_"+httpType+"_"+checkType], ps) } /** 功能:读取swagger的生成json 作者:黄海 时间:2020-03-16 */ func readSwaggerJson() interface{} { //读取doc目录下的swagger.json swaggerFile := "./docs/swagger.json" if !CommonUtil.Exists(swaggerFile) { swaggerFile = "." + swaggerFile } if !CommonUtil.Exists(swaggerFile) { swaggerFile = "/usr/local/dsMin/dsSzxy/docs/swagger.json" } f, err := os.Open(swaggerFile) if err != nil { log.Fatal("读取swagger.json失败!") return nil } content, _ := ioutil.ReadAll(f) var jsonBody interface{} err = json.Unmarshal(content, &jsonBody) if err != nil { fmt.Println("ERROR: ", err.Error()) return nil } return jsonBody } /* 功能:当错误发生时,返回的结构体 */ type ResultStruct struct { InterfaceName string HttpType string Parameter string Message string } /** 功能:封装接收参数 作者:黄海 时间:2020-05-22 */ func getInputParameter(c *gin.Context, httpType string, parameterName string) string { var p string if httpType == "get" { p = c.Query(parameterName) } else { p = c.PostForm(parameterName) } return p } /** 功能:检查必须填写参数是不是为空 作者:黄海 时间:2020-05-22 */ func checkParaIsEmpty(p string, must bool, interName string, httpType string, parameterName string) (bool, ResultStruct) { //1、说是需要 required,结果没传输 -->死罪 //2、说是不需要 required,需要检查业务合法性 -->待定 var resultStruct ResultStruct //为空,需要检查,禁止 if p == "" && must { resultStruct.InterfaceName = interName resultStruct.HttpType = httpType resultStruct.Parameter = parameterName resultStruct.Message = "参数" + parameterName + "没有找到!" return false, resultStruct } return true, resultStruct } /** 功能:通用检查器 作者:黄海 时间:2020-05-22 非空逻辑检查的结果有,1: []parameterStruct:其实是通过常检查(非空逻辑检查)时, */ func commonIsLegal(c *gin.Context, interName string, n int) (bool, ResultStruct, string, []parameterStruct) { var resultStruct ResultStruct var inputParameter string //接口传入的请求方式:get?post? httpType := strings.ToLower(c.Request.Method) var result = make([]parameterStruct, 0) //1、是不是需要检查 key := interName + "_" + httpType + "_" + checkTagsArray[n] //注意这里的数组索引值应该与CheckHandler.go中规定的检查器数组下标相一致 _, ok := parameterMap[key] if ok { //存在本检查器需要检查的参数 arr := parameterMap[key] //这里一个[]map[string]struct for i := 0; i < len(arr); i++ { paraStruct := arr[i] //获取输入的参数 inputParameter = getInputParameter(c, httpType, paraStruct.parameterName) //检查必填写参数的合法性 success, resultStruct := checkParaIsEmpty(inputParameter, paraStruct.must, interName, httpType, paraStruct.parameterName) if !success { return success, resultStruct, httpType, nil } //输入的参数值 paraStruct.inputParameterValue = inputParameter //结果 result = append(result, paraStruct) } } return true, resultStruct, httpType, result }