sign.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. package middleware
  2. import (
  3. "bytes"
  4. "crypto/md5"
  5. "encoding/hex"
  6. "encoding/json"
  7. "github.com/gin-gonic/gin"
  8. "io/ioutil"
  9. "lzyd-user-api/utils"
  10. "net/http"
  11. "net/url"
  12. "sort"
  13. "strings"
  14. )
  15. /**
  16. Sign的格式如下:
  17. 所有的请求参数加上appkey=lzwg-app-N78ya51qaz2wsx!排序后,再MD5
  18. */
  19. const AppKey string = "lzyd-sign-7c423d19cb2b"
  20. func ValidSign(forceValid bool) gin.HandlerFunc {
  21. return func(c *gin.Context) {
  22. // 暂时不对swagger做强校验
  23. if strings.Contains(c.Request.RequestURI, "swagger") {
  24. c.Next()
  25. return
  26. }
  27. if strings.Contains(c.Request.Header.Get("Referer"), "swagger") {
  28. c.Next()
  29. return
  30. }
  31. if !forceValid {
  32. c.Next()
  33. return
  34. }
  35. validSign(c, AppKey)
  36. }
  37. }
  38. //从Header验证参数
  39. func ValidHeaderParams() gin.HandlerFunc {
  40. return func(c *gin.Context) {
  41. //判断是否合法请求
  42. client := c.Request.Header.Get("client")
  43. guid := c.Request.Header.Get("guid")
  44. timestamp := c.Request.Header.Get("timestamp")
  45. sig := c.Request.Header.Get("sig")
  46. if client == "2" { //wap鉴权
  47. //sig:md5(client+'lz2019_random'+uuid+timestamp)
  48. _sig := Md5Encode(client + "lz2019_random" + guid + timestamp)
  49. if _sig == sig { //鉴权通过
  50. //fmt.Println("_sig == sig")
  51. //c.JSON(http.StatusOK, gin.H{"message": "授权成功"})
  52. c.Next()
  53. } else { //请求非法
  54. //fmt.Println("_sig != sig")
  55. c.Abort()
  56. c.JSON(http.StatusForbidden, gin.H{"message": "访问未授权"})
  57. // return可省略, 只要前面执行Abort()就可以让后面的handler函数不再执行
  58. return
  59. }
  60. } else {
  61. c.Next()
  62. }
  63. }
  64. }
  65. func validSign(c *gin.Context, appKey string) {
  66. var (
  67. inSign string
  68. outSign string
  69. )
  70. if c.Request.Method == "GET" {
  71. values := c.Request.URL.Query()
  72. if len(values) <= 0 {
  73. c.Next()
  74. return
  75. }
  76. inSign = values.Get("sign")
  77. if len(inSign) == 0 {
  78. c.JSON(http.StatusOK, gin.H{
  79. "code": -1,
  80. "message": "未传入签名参数",
  81. })
  82. c.Abort()
  83. return
  84. }
  85. outSign = calculateSignFromValues(values, appKey)
  86. } else {
  87. c.Request.ParseMultipartForm(32 << 20)
  88. formData := c.Request.PostForm
  89. if len(formData) > 0 {
  90. inSign = formData.Get("sign")
  91. if len(inSign) == 0 {
  92. c.JSON(http.StatusOK, gin.H{
  93. "code": -1,
  94. "message": "未传入签名参数",
  95. })
  96. c.Abort()
  97. return
  98. }
  99. outSign = calculateSignFromValues(formData, appKey)
  100. } else {
  101. var params map[string]interface{}
  102. data, _ := c.GetRawData()
  103. err := json.Unmarshal(data, &params)
  104. if err != nil {
  105. panic(err)
  106. }
  107. inSign = utils.Interface2String(params["sign"])
  108. if len(inSign) == 0 {
  109. c.JSON(http.StatusOK, gin.H{
  110. "code": -1,
  111. "message": "未传入签名参数",
  112. })
  113. c.Abort()
  114. return
  115. }
  116. outSign = calculateSignFromJsonBody(params, appKey)
  117. // 很关键,把读过的字节流重新放到body
  118. c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(data))
  119. }
  120. }
  121. if outSign != inSign {
  122. c.JSON(http.StatusOK, gin.H{
  123. "code": -1,
  124. "message": "签名验证错误",
  125. })
  126. c.Abort()
  127. }
  128. c.Next()
  129. }
  130. func calculateSignFromValues(values url.Values, appKey string) string {
  131. values.Del("sign")
  132. values.Add("secret", appKey)
  133. if len(values) > 0 {
  134. // 先对Key进行排序
  135. var keywords []string
  136. for key, _ := range values {
  137. keywords = append(keywords, key)
  138. }
  139. sort.Strings(keywords)
  140. // 再根据Key查找参数Map, 并拼接成字符串
  141. var stringBuffer bytes.Buffer
  142. keywordsCnt := len(keywords)
  143. for i := 0; i < keywordsCnt-1; i++ {
  144. keyword := keywords[i]
  145. stringBuffer.WriteString(keyword + "=" + values.Get(keyword))
  146. stringBuffer.WriteString("&")
  147. }
  148. lastKeyword := keywords[keywordsCnt-1]
  149. stringBuffer.WriteString(lastKeyword + "=" + values.Get(lastKeyword))
  150. // 最后MD5加密
  151. hash := md5.New()
  152. hash.Write(stringBuffer.Bytes())
  153. return hex.EncodeToString(hash.Sum(nil))
  154. }
  155. return ""
  156. }
  157. func calculateSignFromJsonBody(params map[string]interface{}, appKey string) string {
  158. delete(params, "sign")
  159. params["secret"] = appKey
  160. if len(params) > 0 {
  161. // 先对Key进行排序
  162. var keywords []string
  163. for key, _ := range params {
  164. keywords = append(keywords, key)
  165. }
  166. sort.Strings(keywords)
  167. // 再根据Key查找参数Map, 并拼接成字符串
  168. var stringBuffer bytes.Buffer
  169. keywordsCnt := len(keywords)
  170. for i := 0; i < keywordsCnt-1; i++ {
  171. keyword := keywords[i]
  172. stringBuffer.WriteString(keyword + "=" + utils.Interface2String(params[keyword]))
  173. stringBuffer.WriteString("&")
  174. }
  175. lastKeyword := keywords[keywordsCnt-1]
  176. stringBuffer.WriteString(lastKeyword + "=" + utils.Interface2String(params[lastKeyword]))
  177. // 最后MD5加密
  178. hash := md5.New()
  179. hash.Write(stringBuffer.Bytes())
  180. return hex.EncodeToString(hash.Sum(nil))
  181. }
  182. return ""
  183. }
  184. // 生成32位md5字串
  185. func Md5Encode(s string) string {
  186. h := md5.New()
  187. h.Write([]byte(s))
  188. return hex.EncodeToString(h.Sum(nil))
  189. }