package utils import ( "bytes" "crypto/md5" "encoding/hex" "encoding/json" "github.com/gin-gonic/gin" "io/ioutil" "net/http" "net/url" "sort" "strings" ) /** Sign的格式如下: 所有的请求参数加上appkey=lzwg-app-N78ya51qaz2wsx!排序后,再MD5 */ const AppKey string = "lzyd-sign-7c423d19cb2b" func ValidSign(forceValid bool) gin.HandlerFunc { return func(c *gin.Context) { // 暂时不对swagger做强校验 if strings.Contains(c.Request.RequestURI, "swagger") { c.Next() return } if strings.Contains(c.Request.Header.Get("Referer"), "swagger") { c.Next() return } if !forceValid { c.Next() return } validSign(c, AppKey) } } //从Header验证参数 func ValidHeaderParams() gin.HandlerFunc { return func(c *gin.Context) { //判断是否合法请求 client := c.Request.Header.Get("client") guid := c.Request.Header.Get("guid") timestamp := c.Request.Header.Get("timestamp") sig := c.Request.Header.Get("sig") if client == "2" { //wap鉴权 //sig:md5(client+'lz2019_random'+uuid+timestamp) _sig := Md5Encode(client + "lz2019_random" + guid + timestamp) if _sig == sig { //鉴权通过 //fmt.Println("_sig == sig") //c.JSON(http.StatusOK, gin.H{"message": "授权成功"}) c.Next() } else { //请求非法 //fmt.Println("_sig != sig") c.Abort() c.JSON(http.StatusForbidden, gin.H{"message": "访问未授权"}) // return可省略, 只要前面执行Abort()就可以让后面的handler函数不再执行 return } } else { c.Next() } } } func validSign(c *gin.Context, appKey string) { var ( inSign string outSign string ) if c.Request.Method == "GET" { values := c.Request.URL.Query() if len(values) <= 0 { c.Next() return } inSign = values.Get("sign") if len(inSign) == 0 { c.JSON(http.StatusOK, gin.H{ "code": -1, "message": "未传入签名参数", }) c.Abort() return } outSign = calculateSignFromValues(values, appKey) } else { c.Request.ParseMultipartForm(32 << 20) formData := c.Request.PostForm if len(formData) > 0 { inSign = formData.Get("sign") if len(inSign) == 0 { c.JSON(http.StatusOK, gin.H{ "code": -1, "message": "未传入签名参数", }) c.Abort() return } outSign = calculateSignFromValues(formData, appKey) } else { var params map[string]interface{} data, _ := c.GetRawData() err := json.Unmarshal(data, ¶ms) if err != nil { panic(err) } inSign = Interface2String(params["sign"]) if len(inSign) == 0 { c.JSON(http.StatusOK, gin.H{ "code": -1, "message": "未传入签名参数", }) c.Abort() return } outSign = calculateSignFromJsonBody(params, appKey) // 很关键,把读过的字节流重新放到body c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data)) } } if outSign != inSign { c.JSON(http.StatusOK, gin.H{ "code": -1, "message": "签名验证错误", }) c.Abort() } c.Next() } func calculateSignFromValues(values url.Values, appKey string) string { values.Del("sign") values.Add("secret", appKey) if len(values) > 0 { // 先对Key进行排序 var keywords []string for key, _ := range values { keywords = append(keywords, key) } sort.Strings(keywords) // 再根据Key查找参数Map, 并拼接成字符串 var stringBuffer bytes.Buffer keywordsCnt := len(keywords) for i := 0; i < keywordsCnt-1; i++ { keyword := keywords[i] stringBuffer.WriteString(keyword + "=" + values.Get(keyword)) stringBuffer.WriteString("&") } lastKeyword := keywords[keywordsCnt-1] stringBuffer.WriteString(lastKeyword + "=" + values.Get(lastKeyword)) // 最后MD5加密 hash := md5.New() hash.Write(stringBuffer.Bytes()) return hex.EncodeToString(hash.Sum(nil)) } return "" } func calculateSignFromJsonBody(params map[string]interface{}, appKey string) string { delete(params, "sign") params["secret"] = appKey if len(params) > 0 { // 先对Key进行排序 var keywords []string for key, _ := range params { keywords = append(keywords, key) } sort.Strings(keywords) // 再根据Key查找参数Map, 并拼接成字符串 var stringBuffer bytes.Buffer keywordsCnt := len(keywords) for i := 0; i < keywordsCnt-1; i++ { keyword := keywords[i] stringBuffer.WriteString(keyword + "=" + Interface2String(params[keyword])) stringBuffer.WriteString("&") } lastKeyword := keywords[keywordsCnt-1] stringBuffer.WriteString(lastKeyword + "=" + Interface2String(params[lastKeyword])) // 最后MD5加密 hash := md5.New() hash.Write(stringBuffer.Bytes()) return hex.EncodeToString(hash.Sum(nil)) } return "" }