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