You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

291 lines
8.3 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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
}