-
Notifications
You must be signed in to change notification settings - Fork 0
/
jwt.go
149 lines (129 loc) · 3.75 KB
/
jwt.go
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
package userutil
import (
"context"
"encoding/json"
"errors"
"github.com/golang-jwt/jwt/v4"
"github.com/soxft/openid-go/app/model"
"github.com/soxft/openid-go/config"
"github.com/soxft/openid-go/library/toolutil"
"github.com/soxft/openid-go/process/dbutil"
"github.com/soxft/openid-go/process/redisutil"
"gorm.io/gorm"
"log"
"regexp"
"time"
)
// GetJwtFromAuth
// 从 Authorization 中获取JWT
func GetJwtFromAuth(Authorization string) string {
reg, _ := regexp.Compile(`^Bearer\s+(.*)$`)
if reg.MatchString(Authorization) {
return reg.FindStringSubmatch(Authorization)[1]
}
return ""
}
// GenerateJwt
// @description generate JWT token for user
func GenerateJwt(userId int, clientIp string) (string, error) {
var userInfo model.Account
err := dbutil.D.Model(model.Account{}).Select("id, username, email, last_time, last_ip").Where(model.Account{ID: userId}).Take(&userInfo).Error
if errors.Is(err, gorm.ErrRecordNotFound) {
return "", nil
} else if err != nil {
return "", err
}
timeNow := time.Now().Unix()
uInfo := UserInfo{
UserId: userId,
Username: userInfo.Username,
Email: userInfo.Email,
LastTime: timeNow,
}
// update last login info
setUserLastLogin(userInfo.ID, timeNow, clientIp)
return jwt.NewWithClaims(jwt.SigningMethodHS512, JwtClaims{
ID: generateJti(uInfo),
ExpireAt: time.Now().Add(24 * 30 * time.Hour).Unix(),
IssuedAt: time.Now().Unix(),
Issuer: config.Server.Title,
Username: userInfo.Username,
UserId: userId,
Email: userInfo.Email,
LastTime: timeNow,
}).SignedString([]byte(config.Jwt.Secret))
}
// CheckPermission
// @description check user permission
func CheckPermission(ctx context.Context, _jwt string) (UserInfo, error) {
JwtClaims, err := JwtDecode(_jwt)
if err != nil {
return UserInfo{}, err
}
if checkJti(ctx, JwtClaims.ID) != nil {
return UserInfo{}, ErrJwtExpired
}
return UserInfo{
UserId: JwtClaims.UserId,
Username: JwtClaims.Username,
Email: JwtClaims.Email,
LastTime: JwtClaims.LastTime,
}, nil
}
// JwtDecode
// @description check JWT token
func JwtDecode(_jwt string) (JwtClaims, error) {
token, err := jwt.ParseWithClaims(_jwt, &JwtClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(config.Jwt.Secret), nil
})
if err != nil {
return JwtClaims{}, err
}
if claims, ok := token.Claims.(*JwtClaims); ok && token.Valid {
return *claims, nil
}
return JwtClaims{}, errors.New("jwt token error")
}
// SetJwtExpire
// @description 标记JWT过期
func SetJwtExpire(c context.Context, _jwt string) error {
JwtClaims, _ := JwtDecode(_jwt)
_redis := redisutil.RDB
ttl := JwtClaims.ExpireAt - time.Now().Unix()
err := _redis.SetEx(c, getJwtExpiredKey(JwtClaims.ID), "1", time.Duration(ttl)).Err()
if err != nil {
log.Printf("[ERROR] SetJwtExpire: %s", err.Error())
return errors.New("set jwt expire error")
}
return nil
}
// checkJti
func checkJti(ctx context.Context, jti string) error {
_redis := redisutil.RDB
expired, err := _redis.Exists(ctx, getJwtExpiredKey(jti)).Result()
if err != nil {
log.Printf("[ERROR] checkJti: %s", err.Error())
return errors.New("check jti error")
}
if expired == 1 {
return ErrJwtExpired
}
return nil
}
// generateJti 创建 Jti
func generateJti(user UserInfo) string {
JtiJson, _ := json.Marshal(map[string]string{
"username": user.Username,
"randStr": toolutil.RandStr(32),
"time": time.Now().Format("150405"),
})
_jti := toolutil.Md5(string(JtiJson))
return _jti
}
func setUserLastLogin(userId int, lastTime int64, lastIp string) {
dbutil.D.Model(&model.Account{}).Where(model.Account{ID: userId}).Updates(&model.Account{LastTime: lastTime, LastIp: lastIp})
}
// getJwtExpiredKey
func getJwtExpiredKey(jti string) string {
return config.RedisPrefix + ":jti:expired:" + jti
}