1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package middleware
import (
"bytes"
"errors"
"fmt"
"gin-vue-admin/global"
"gin-vue-admin/model"
"gin-vue-admin/model/request"
"gin-vue-admin/model/response"
"gin-vue-admin/service"
"github.com/dgrijalva/jwt-go"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
"io/ioutil"
"net/http"
"strconv"
"time"
)
func JWTAuth() gin.HandlerFunc {
return func(c *gin.Context) {
// 我们这里jwt鉴权取头部信息 x-token 登录时回返回token信息 这里前端需要把token存储到cookie或者本地localStorage中 不过需要跟后端协商过期时间 可以约定刷新令牌或者重新登录
token := c.Request.Header.Get("x-token")
fmt.Println("token:" + token)
if token == "" {
response.FailWithDetailedCode(8, gin.H{"reload": true}, "请登录", c)
c.Abort()
return
}
if service.IsBlacklist(token) { //您的帐户异地登陆或令牌失效
response.FailWithDetailedCode(8, gin.H{"reload": true}, "请登录", c)
c.Abort()
return
}
j := NewJWT()
// parseToken 解析token包含的信息
claims, err := j.ParseToken(token)
if err != nil {
if err == TokenExpired { //授权已过期
response.FailWithDetailedCode(8, gin.H{"reload": true}, "请登录", c)
c.Abort()
return
}
response.FailWithDetailedCode(8, gin.H{"reload": true}, err.Error(), c)
c.Abort()
return
}
if err, _ = service.FindUserByUuid(claims.UUID.String()); err != nil {
_ = service.JsonInBlacklist(model.JwtBlacklist{Jwt: token})
response.FailWithDetailedCode(8, gin.H{"reload": true}, err.Error(), c)
c.Abort()
}
if claims.ExpiresAt-time.Now().Unix() < claims.BufferTime {
claims.ExpiresAt = time.Now().Unix() + global.GVA_CONFIG.JWT.ExpiresTime
newToken, _ := j.CreateToken(*claims)
newClaims, _ := j.ParseToken(newToken)
c.Header("new-token", newToken)
c.Header("new-expires-at", strconv.FormatInt(newClaims.ExpiresAt, 10))
if global.GVA_CONFIG.System.UseMultipoint {
err, RedisJwtToken := service.GetRedisJWT(newClaims.Mobile)
if err != nil {
global.GVA_LOG.Error("get redis jwt failed", zap.Any("err", err))
} else { // 当之前的取成功时才进行拉黑操作
_ = service.JsonInBlacklist(model.JwtBlacklist{Jwt: RedisJwtToken})
}
// 无论如何都要记录当前的活跃状态
_ = service.SetRedisJWT(newToken, newClaims.Mobile)
}
}
var body []byte
if c.Request.Method != http.MethodGet {
body, _ = ioutil.ReadAll(c.Request.Body)
fmt.Println(string(body) + "======userid:" + strconv.Itoa(int(claims.ID)))
//把读过的字节流重新放到body
c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
}
c.Set("claims", claims)
c.Next()
}
}
type JWT struct {
SigningKey []byte
}
var (
TokenExpired = errors.New("Token is expired")
TokenNotValidYet = errors.New("Token not active yet")
TokenMalformed = errors.New("That's not even a token")
TokenInvalid = errors.New("Couldn't handle this token:")
)
func NewJWT() *JWT {
return &JWT{
[]byte(global.GVA_CONFIG.JWT.SigningKey),
}
}
// 创建一个token
func (j *JWT) CreateToken(claims request.CustomClaims) (string, error) {
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString(j.SigningKey)
}
// 解析 token
func (j *JWT) ParseToken(tokenString string) (*request.CustomClaims, error) {
token, err := jwt.ParseWithClaims(tokenString, &request.CustomClaims{}, func(token *jwt.Token) (i interface{}, e error) {
return j.SigningKey, nil
})
if err != nil {
if ve, ok := err.(*jwt.ValidationError); ok {
if ve.Errors&jwt.ValidationErrorMalformed != 0 {
return nil, TokenMalformed
} else if ve.Errors&jwt.ValidationErrorExpired != 0 {
// Token is expired
return nil, TokenExpired
} else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 {
return nil, TokenNotValidYet
} else {
return nil, TokenInvalid
}
}
}
if token != nil {
if claims, ok := token.Claims.(*request.CustomClaims); ok && token.Valid {
return claims, nil
}
return nil, TokenInvalid
} else {
return nil, TokenInvalid
}
}
// 更新token
//func (j *JWT) RefreshToken(tokenString string) (string, error) {
// jwt.TimeFunc = func() time.Time {
// return time.Unix(0, 0)
// }
// token, err := jwt.ParseWithClaims(tokenString, &request.CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
// return j.SigningKey, nil
// })
// if err != nil {
// return "", err
// }
// if claims, ok := token.Claims.(*request.CustomClaims); ok && token.Valid {
// jwt.TimeFunc = time.Now
// claims.StandardClaims.ExpiresAt = time.Now().Unix() + 60*60*24*7
// return j.CreateToken(*claims)
// }
// return "", TokenInvalid
//}