-
Notifications
You must be signed in to change notification settings - Fork 0
/
jwt.go
124 lines (113 loc) · 3.21 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
package jwt
import (
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"strings"
"time"
orm "github.com/coolray-dev/raydash/database"
model "github.com/coolray-dev/raydash/models"
"github.com/gbrlsnchs/jwt/v3"
"github.com/google/uuid"
)
// TokenPayload is a convented JWT Payload struct
type TokenPayload struct {
jwt.Payload
UID uint64 `json:"uid"`
Username string `json:"username"`
}
// Verify validate token with given key
func Verify(token []byte, key []byte) (*TokenPayload, error) {
var plain TokenPayload
// Register expiration and issuedAt validator
now := time.Now()
iatValidator := jwt.IssuedAtValidator(now)
expValidator := jwt.ExpirationTimeValidator(now)
validatePayload := jwt.ValidatePayload(&plain.Payload, iatValidator, expValidator)
// Registor Algorithm
hs := jwt.NewHS512(key)
// Call jwt package to verify
_, err := jwt.Verify(token, hs, &plain, validatePayload)
if err != nil {
return nil, fmt.Errorf("Token verifying error: %w", err)
}
return &plain, nil
}
// SignRefreshToken signs a refresh token of a user
func SignRefreshToken(user *model.User) (token string, err error) {
var key []byte
key, err = user.GetJwtKey()
if err != nil {
return
}
var hs = jwt.NewHS512(key)
now := time.Now()
plain := TokenPayload{ // defined in jwthelper.go
Payload: jwt.Payload{
Issuer: "RayDash",
Subject: "RefreshToken",
Audience: jwt.Audience{},
ExpirationTime: jwt.NumericDate(now.Add(24 * time.Hour)), // Hard code 1 day refreshToken expire time for now
NotBefore: jwt.NumericDate(now),
IssuedAt: jwt.NumericDate(now),
JWTID: uuid.New().String(),
},
UID: user.ID,
Username: user.Username,
}
var tokenb []byte
tokenb, err = jwt.Sign(plain, hs)
token = string(tokenb)
if user.Token == nil {
user.Token = make(map[string]time.Time)
}
user.Token[token] = now.Add(24 * time.Hour)
if err := orm.DB.Save(&user).Error; err != nil {
return "", fmt.Errorf("Database error: %w", err)
}
return token, err
}
// SignAccessToken signs a access token of a user
func SignAccessToken(user *model.User) (token string, err error) {
var key []byte
key, err = user.GetJwtKey()
if err != nil {
return
}
var hs = jwt.NewHS512(key)
now := time.Now()
plain := TokenPayload{ // defined in jwthelper
Payload: jwt.Payload{
Issuer: "RayDash",
Subject: "AccessToken",
Audience: jwt.Audience{},
ExpirationTime: jwt.NumericDate(now.Add(5 * time.Minute)), // Hard code 5 min accessToken expire time for now
NotBefore: jwt.NumericDate(now),
IssuedAt: jwt.NumericDate(now),
JWTID: uuid.New().String(),
},
UID: user.ID,
Username: user.Username,
}
var tokenb []byte
tokenb, err = jwt.Sign(plain, hs)
token = string(tokenb)
return token, err
}
// ParseUID get uid from a jwt
func ParseUID(token string) (uint64, error) {
tokenSplit := strings.Split(token, ".")
if len(tokenSplit) != 3 {
return 0, errors.New("Invalid JWT Token")
}
var payload TokenPayload
dec, base64Err := base64.RawURLEncoding.DecodeString(tokenSplit[1])
if base64Err != nil {
return 0, base64Err
}
if err := json.Unmarshal(dec, &payload); err != nil {
return 0, err
}
return payload.UID, nil
}