jwt.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. package client
  2. import (
  3. "errors"
  4. "fmt"
  5. "github.com/dgrijalva/jwt-go"
  6. "github.com/gin-gonic/gin"
  7. "net/http"
  8. "strconv"
  9. "strings"
  10. "time"
  11. "ulink-admin/config"
  12. "ulink-admin/frame"
  13. "ulink-admin/modules/system/models/model"
  14. "ulink-admin/pkg/base"
  15. "ulink-admin/pkg/jwt/common"
  16. )
  17. // JWTAuth 中间件,检查token
  18. func JWTAuth() frame.IMidHandler {
  19. return func(c *frame.Context) {
  20. //调用过滤去将放行的请求先放行
  21. if DoSquare(c.Context) {
  22. return
  23. }
  24. token := c.Request.Header.Get("Authorization")
  25. if token == "" {
  26. c.JSON(http.StatusOK, gin.H{
  27. "status": 401,
  28. "msg": "请求未携带token,无权限访问",
  29. })
  30. c.Abort()
  31. return
  32. }
  33. s := strings.Split(token, " ")
  34. if len(s) != 2 {
  35. c.JSON(http.StatusOK, gin.H{
  36. "status": 401,
  37. "msg": "token格式错误,无权限访问",
  38. })
  39. c.Abort()
  40. return
  41. }
  42. j := NewJWT()
  43. // parseToken 解析token包含的信息
  44. claims, err := j.ParseToken(s[1])
  45. if err != nil {
  46. c.JSON(http.StatusOK, gin.H{
  47. "status": 401,
  48. "msg": err.Error(),
  49. })
  50. c.Abort()
  51. return
  52. }
  53. appServer := config.GetServerCfg()
  54. lock := appServer.Lock
  55. if lock == "0" {
  56. get, err := base.RedisDB.GET(claims.RedisKey)
  57. if err == nil {
  58. if !(get == s[1]) {
  59. c.JSON(http.StatusOK, gin.H{
  60. "status": 401,
  61. "msg": "您的账号已在其他终端登录,请重新登录",
  62. })
  63. c.Abort()
  64. return
  65. }
  66. }
  67. }
  68. if err != nil {
  69. c.JSON(http.StatusOK, gin.H{
  70. "status": 401,
  71. "msg": err.Error(),
  72. })
  73. c.Abort()
  74. return
  75. }
  76. // 继续交由下一个路由处理,并将解析出的信息传递下去
  77. c.Set("claims", claims)
  78. }
  79. }
  80. // JWT 签名结构
  81. type JWT struct {
  82. SigningKey []byte
  83. }
  84. // 一些常量
  85. var (
  86. TokenExpired = errors.New("授权已过期")
  87. TokenNotValidYet = errors.New("token not active yet")
  88. TokenMalformed = errors.New("令牌非法")
  89. TokenInvalid = errors.New("couldn't handle this token")
  90. SignKey = "0df9b8db-6f7c-d713-eeab-ecb317696042"
  91. userTypes = map[string]string{"00": "SystemUser:", "01": "WechatUser:"}
  92. )
  93. // CustomClaims 载荷,可以加一些自己需要的信息
  94. type CustomClaims struct {
  95. UserInfo *model.SysMember `json:"userInfo"`
  96. jwt.StandardClaims
  97. RedisKey string
  98. RedisTimeOut int
  99. }
  100. // NewJWT 新建一个jwt实例
  101. func NewJWT() *JWT {
  102. return &JWT{
  103. []byte(GetSignKey()),
  104. }
  105. }
  106. // GetSignKey 获取signKey
  107. func GetSignKey() string {
  108. return SignKey
  109. }
  110. // SetSignKey 设置SignKey
  111. func SetSignKey(key string) string {
  112. SignKey = key
  113. return SignKey
  114. }
  115. // CreateToken 生成一个token
  116. func (j *JWT) CreateToken(claims CustomClaims) (string, error) {
  117. token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
  118. return token.SignedString(j.SigningKey)
  119. }
  120. // CreateUserToken 生成含有用户信息的token
  121. func (j *JWT) CreateUserToken(loginType string, u *model.SysMember) (string, error) {
  122. jwtConfig := config.GetJwtConfig()
  123. strInt64 := strconv.FormatInt(jwtConfig.TimeOut.Nanoseconds()*3600, 10)
  124. sec, _ := strconv.Atoi(strInt64)
  125. claims := jwt.NewWithClaims(jwt.SigningMethodHS256, CustomClaims{
  126. UserInfo: u,
  127. StandardClaims: jwt.StandardClaims{
  128. //设置token小时时效
  129. ExpiresAt: time.Now().Add(jwtConfig.TimeOut * time.Hour).Unix(),
  130. IssuedAt: time.Now().Unix(),
  131. Issuer: jwtConfig.Issuer,
  132. },
  133. RedisKey: fmt.Sprintf("%s|%s|%s", common.LOGIN_MEMBER, loginType, u.UserName),
  134. RedisTimeOut: sec,
  135. })
  136. return claims.SignedString(j.SigningKey)
  137. }
  138. // ParseToken 解析Token
  139. func (j *JWT) ParseToken(tokenString string) (*CustomClaims, error) {
  140. token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
  141. return j.SigningKey, nil
  142. })
  143. if err != nil {
  144. if ve, ok := err.(*jwt.ValidationError); ok {
  145. if ve.Errors&jwt.ValidationErrorMalformed != 0 {
  146. return nil, TokenMalformed
  147. } else if ve.Errors&jwt.ValidationErrorExpired != 0 {
  148. // Token is expired
  149. return nil, TokenExpired
  150. } else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 {
  151. return nil, TokenNotValidYet
  152. } else {
  153. return nil, TokenInvalid
  154. }
  155. }
  156. }
  157. if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
  158. return claims, nil
  159. }
  160. return nil, TokenInvalid
  161. }
  162. // RefreshToken 更新token
  163. func (j *JWT) RefreshToken(tokenString string) (string, error) {
  164. jwt.TimeFunc = func() time.Time {
  165. return time.Unix(0, 0)
  166. }
  167. token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
  168. return j.SigningKey, nil
  169. })
  170. if err != nil {
  171. return "", err
  172. }
  173. if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
  174. jwt.TimeFunc = time.Now
  175. claims.StandardClaims.ExpiresAt = time.Now().Add(24 * time.Hour).Unix()
  176. return j.CreateToken(*claims)
  177. }
  178. return "", TokenInvalid
  179. }