token.go 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. package token
  2. import (
  3. "crypto/hmac"
  4. "crypto/sha256"
  5. "encoding/hex"
  6. "errors"
  7. "fmt"
  8. "mtp2_if/config"
  9. "mtp2_if/global/e"
  10. "mtp2_if/logger"
  11. "mtp2_if/rediscli"
  12. "net/http"
  13. "runtime"
  14. "strconv"
  15. "strings"
  16. "time"
  17. "github.com/gin-gonic/gin"
  18. )
  19. // TouristToken 游客Token
  20. var TouristToken string = "c886a057f3d820d4dbc41473686c7c2d"
  21. // CheckToken Token校验
  22. func CheckToken(loginid string, token string, group string) (string, error) {
  23. key := ""
  24. if len(group) == 0 {
  25. key = fmt.Sprintf("monitor:online_loginid::%s", loginid)
  26. } else {
  27. key = fmt.Sprintf("monitor:online_loginid:%s:%s", loginid, group)
  28. }
  29. field := "Token"
  30. realToken, err := rediscli.GetRedisClient().HGet(key, field).Result()
  31. if err != nil {
  32. return "", err
  33. }
  34. if realToken != token {
  35. return "", errors.New("token is invalid")
  36. }
  37. // 获取UserID
  38. userID, err := rediscli.GetRedisClient().HGet(key, "UserID").Result()
  39. return userID, err
  40. }
  41. // Auth Token校验中间件
  42. func Auth() gin.HandlerFunc {
  43. return func(c *gin.Context) {
  44. // if config.SerCfg.GetDebugMode() {
  45. // c.Next()
  46. // return
  47. // }
  48. // windows下方便开发调试, 不做token校验
  49. if config.SerCfg.GetDebugMode() &&
  50. runtime.GOOS == "windows" {
  51. c.Next()
  52. return
  53. }
  54. var code int
  55. var data interface{}
  56. userID := ""
  57. code = e.SUCCESS
  58. token := c.GetHeader("Authorization")
  59. if token == "" {
  60. // Token缺失
  61. code = e.ERROR_AUTH_CHECK_TOKEN_FAIL
  62. } else {
  63. // 获取loginid
  64. s := strings.Split(token, "_")
  65. loginid := s[0]
  66. // 支持分组功能
  67. group := ""
  68. if len(s) == 3 {
  69. group = s[2]
  70. }
  71. var err error
  72. userID, err = CheckToken(loginid, token, group)
  73. if err != nil {
  74. // Token错误
  75. code = e.ERROR_AUTH_CHECK_TOKEN_FAIL
  76. }
  77. }
  78. // Token检验失败
  79. if code != e.SUCCESS {
  80. c.JSON(http.StatusUnauthorized, gin.H{
  81. "code": code,
  82. "msg": e.GetMsg(code),
  83. "data": data,
  84. })
  85. c.Abort()
  86. return
  87. }
  88. // FIXME: - 针对POST接口,应判断传入TOKEN对应的用户是否正确(比如判断UserID或AccountID是否对得上等),后期处理
  89. // if c.Request.Method == "POST" {
  90. c.Set("requserid", userID)
  91. // }
  92. // 是否已开启APIKey检验模式
  93. if config.SerCfg.GetApiKeyMode() {
  94. timestamp := c.GetHeader("Timestamp")
  95. verification := c.GetHeader("Verification")
  96. if timestamp == "" || token == "" || verification == "" {
  97. c.JSON(http.StatusUnauthorized, gin.H{
  98. "code": e.ERROR,
  99. "msg": "apikey_err1",
  100. "data": struct{}{},
  101. })
  102. c.Abort()
  103. return
  104. }
  105. // 判断时间,10S之内有效
  106. t, err := strconv.Atoi(timestamp)
  107. if err != nil {
  108. c.JSON(http.StatusUnauthorized, gin.H{
  109. "code": e.ERROR,
  110. "msg": "apikey_err2",
  111. "data": struct{}{},
  112. })
  113. c.Abort()
  114. return
  115. }
  116. now := time.Now().UTC().UnixMilli()
  117. ts := int64(t) - now
  118. if ts < -10*1000 || ts > 10*1000 {
  119. logger.GetLogger().Errorf("t:%v now:%v ts: %v", t, now, ts)
  120. c.JSON(http.StatusUnauthorized, gin.H{
  121. "code": e.ERROR,
  122. "msg": "apikey_err3",
  123. "data": struct{}{},
  124. })
  125. c.Abort()
  126. return
  127. }
  128. s := fmt.Sprintf("%s%s", token, timestamp)
  129. hashed := hmac.New(sha256.New, []byte(config.SerCfg.WebCfg.ApiKey))
  130. hashed.Write([]byte(s))
  131. h := hex.EncodeToString(hashed.Sum(nil))
  132. if h == "" {
  133. c.JSON(http.StatusUnauthorized, gin.H{
  134. "code": e.ERROR,
  135. "msg": "apikey_err4",
  136. "data": struct{}{},
  137. })
  138. c.Abort()
  139. return
  140. }
  141. if h != verification {
  142. c.JSON(http.StatusUnauthorized, gin.H{
  143. "code": e.ERROR,
  144. "msg": "apikey_err5",
  145. "data": struct{}{},
  146. })
  147. c.Abort()
  148. return
  149. }
  150. }
  151. // Token检验成功
  152. c.Next()
  153. }
  154. }
  155. // AuthByHsby 游客鉴权
  156. func AuthByHsby() gin.HandlerFunc {
  157. return func(c *gin.Context) {
  158. // 包含accountID、accountIDs、userID和userIDs等参数需要走正常鉴权
  159. accountID := c.Query("accountID")
  160. accountIDs := c.Query("accountIDs")
  161. userID := c.Query("userID")
  162. userIDs := c.Query("userIDs")
  163. loginID := c.Query("loginID")
  164. if len(accountID) != 0 || len(accountIDs) != 0 || len(userID) != 0 || len(userIDs) != 0 || len(loginID) != 0 {
  165. realToken(c)
  166. return
  167. }
  168. var code int
  169. var data interface{}
  170. code = e.SUCCESS
  171. token := c.GetHeader("Authorization")
  172. if token == "" {
  173. // Token缺失
  174. code = e.ERROR_AUTH_CHECK_TOKEN_FAIL
  175. } else {
  176. // Token带下划线的走正常鉴权
  177. if strings.Contains(token, "_") {
  178. realToken(c)
  179. return
  180. }
  181. if token != TouristToken {
  182. // Token错误
  183. code = e.ERROR_AUTH_CHECK_TOKEN_FAIL
  184. }
  185. }
  186. // Token检验失败
  187. if code != e.SUCCESS {
  188. c.JSON(http.StatusUnauthorized, gin.H{
  189. "code": code,
  190. "msg": e.GetMsg(code),
  191. "data": data,
  192. })
  193. c.Abort()
  194. return
  195. }
  196. // Token检验成功
  197. c.Next()
  198. }
  199. }
  200. func realToken(c *gin.Context) {
  201. // if config.SerCfg.GetDebugMode() {
  202. // c.Next()
  203. // return
  204. // }
  205. var code int
  206. var data interface{}
  207. code = e.SUCCESS
  208. token := c.GetHeader("Authorization")
  209. if token == "" {
  210. // Token缺失
  211. code = e.ERROR_AUTH_CHECK_TOKEN_FAIL
  212. } else {
  213. // 获取loginid
  214. s := strings.Split(token, "_")
  215. loginid := s[0]
  216. // 支持分组功能
  217. group := ""
  218. if len(s) == 3 {
  219. group = s[2]
  220. }
  221. if _, err := CheckToken(loginid, token, group); err != nil {
  222. // Token错误
  223. code = e.ERROR_AUTH_CHECK_TOKEN_FAIL
  224. }
  225. }
  226. // Token检验失败
  227. if code != e.SUCCESS {
  228. c.JSON(http.StatusUnauthorized, gin.H{
  229. "code": code,
  230. "msg": e.GetMsg(code),
  231. "data": data,
  232. })
  233. c.Abort()
  234. return
  235. }
  236. // FIXME: - 针对POST接口,应判断传入TOKEN对应的用户是否正确(比如判断UserID或AccountID是否对得上等),后期处理
  237. // Token检验成功
  238. c.Next()
  239. return
  240. }