|
|
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
|
|
|
}
|