gitee.com/h79/goutils@v1.22.10/auth/jwt/token.go (about) 1 package jwt 2 3 import ( 4 "encoding/base64" 5 "errors" 6 "fmt" 7 "gitee.com/h79/goutils/auth/token" 8 "gitee.com/h79/goutils/common/result" 9 "gitee.com/h79/goutils/common/timer" 10 "github.com/golang-jwt/jwt/v5" 11 "time" 12 ) 13 14 type UpdateJWTClaims func(tk token.Token) jwt.Claims 15 16 // 保证 Token struct implement token.Token 17 var _ token.Token = (*Token)(nil) 18 19 type Token struct { 20 Uid string `json:"uid"` 21 Token string `json:"token"` 22 Session string `json:"-"` //for server and server 23 Extend string `json:"-"` 24 Source token.Source `json:"-"` 25 expire timer.Expire 26 ujc UpdateJWTClaims 27 key token.Key 28 custom interface{} 29 base64 bool 30 } 31 32 func NewToken(key token.Key, ujc UpdateJWTClaims, base64 bool) *Token { 33 return &Token{ 34 ujc: ujc, 35 key: key, 36 base64: base64, 37 } 38 } 39 40 func (tk *Token) WithVar(key string, value interface{}) token.Token { 41 switch key { 42 case token.CSource: 43 tk.Source = value.(token.Source) 44 case token.CSession: 45 tk.Session = value.(string) 46 case token.CExtend: 47 tk.Extend = value.(string) 48 case token.CUid: 49 tk.Uid = value.(string) 50 case token.CCustom: 51 tk.custom = value 52 case token.CIssuedAt: 53 tk.expire.StartIn = value.(int64) 54 case token.CExpiresAt: 55 tk.expire.ExpireIn = value.(int64) 56 } 57 return tk 58 } 59 60 func (tk *Token) GetVar(key string) interface{} { 61 switch key { 62 case token.CSource: 63 return tk.Source 64 case token.CSession: 65 return tk.Session 66 case token.CUid: 67 return tk.Uid 68 case token.CBase64: 69 return tk.base64 70 case token.CCustom: 71 return tk.custom 72 case token.CExtend: 73 return tk.Extend 74 case token.CIssuedAt: 75 return tk.expire.StartIn 76 case token.CExpiresAt: 77 return tk.expire.ExpireIn 78 } 79 return "" 80 } 81 82 func (tk *Token) GetToken() string { 83 return tk.Token 84 } 85 86 // ExpireIn token.Token interface 87 func (tk *Token) ExpireIn() int64 { 88 return tk.key.ExpireIn() 89 } 90 91 // Update token.Token interface 92 func (tk *Token) Update() (string, error) { 93 jwtToken := jwt.NewWithClaims(jwt.SigningMethodHS256, tk.jwtClaims()) 94 tStr, err := jwtToken.SignedString(tk.key.Key()) 95 if err != nil { 96 return "", err 97 } 98 if tk.base64 { 99 tk.Token = base64.StdEncoding.EncodeToString([]byte(tStr)) 100 } else { 101 tk.Token = tStr 102 } 103 return tk.Token, nil 104 } 105 106 func (tk *Token) jwtClaims() jwt.Claims { 107 if tk.ujc != nil { 108 return tk.ujc(tk) 109 } 110 var ex = tk.expire 111 if tk.expire.StartIn <= 0 { 112 ex = timer.NowExpireWithSecond(tk.ExpireIn()) 113 } 114 return &jwtClaims{ 115 Subject: tk.Uid, 116 IssuedAt: jwt.NewNumericDate(time.Unix(ex.StartIn, 0)), 117 ExpiresAt: jwt.NewNumericDate(time.Unix(ex.ExpireIn, 0)), 118 Source: tk.Source, 119 Session: tk.Session, 120 Extend: tk.Extend, 121 } 122 } 123 124 var defJWTFactory jwtFactory 125 126 type jwtFactory struct { 127 } 128 129 func (f *jwtFactory) Create(key token.Key, opts ...token.Option) (token.Token, error) { 130 return NewToken(key, nil, token.IsBase64Enabled(opts...)), nil 131 } 132 133 func (f *jwtFactory) Decode(tk string, opts ...token.Option) (token.Token, error) { 134 if token.IsBase64Enabled(opts...) { 135 return DecodeToken(tk) 136 } 137 return DecodeTokenNoBase64(tk) 138 } 139 140 func (f *jwtFactory) Check(tk string, key token.Key, opts ...token.Option) (token.Token, error) { 141 if token.IsBase64Enabled(opts...) { 142 return VerifyToken(tk, key) 143 } 144 return VerifyTokenNoBase64(tk, key) 145 } 146 147 // DecodeToken 不需要认证,解包里面的信息 148 func DecodeToken(tk string) (token.Token, error) { 149 bytes, er := base64.StdEncoding.DecodeString(tk) 150 if er != nil { 151 return nil, er 152 } 153 return DecodeTokenNoBase64(string(bytes)) 154 } 155 156 func DecodeTokenNoBase64(tk string) (token.Token, error) { 157 158 // for 读取信息,不验证 159 tc := jwtClaims{} 160 jtk, err := jwt.ParseWithClaims(tk, &tc, nil) 161 if jtk != nil { 162 return tc.To(tk), nil 163 } else if errors.Is(err, jwt.ErrTokenMalformed) { 164 fmt.Println("That's not even a token") 165 } else if errors.Is(err, jwt.ErrTokenSignatureInvalid) { 166 // Invalid signature 167 fmt.Println("Invalid signature") 168 } else if errors.Is(err, jwt.ErrTokenExpired) || errors.Is(err, jwt.ErrTokenNotValidYet) { 169 // Token is either expired or not active yet 170 fmt.Println("Timing is everything") 171 } else { 172 fmt.Println("Couldn't handle this token:", err) 173 } 174 return nil, err 175 } 176 177 // VerifyToken 需要认证,解包里面的信息 178 func VerifyToken(tk string, key token.Key) (token.Token, error) { 179 bytes, er := base64.StdEncoding.DecodeString(tk) 180 if er != nil { 181 return nil, er 182 } 183 184 return VerifyTokenNoBase64(string(bytes), key) 185 } 186 187 func VerifyTokenNoBase64(tk string, key token.Key) (token.Token, error) { 188 189 tc := jwtClaims{} 190 jtk, err := jwt.ParseWithClaims(tk, &tc, func(token *jwt.Token) (interface{}, error) { 191 if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { 192 return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) 193 } 194 return key.Key(), nil 195 }) 196 if err == nil && jtk.Valid { 197 tok := tc.To(tk) 198 tok.key = key 199 return tok, nil 200 } 201 code := result.ErrToken 202 if errors.Is(err, jwt.ErrTokenMalformed) { 203 code |= result.TokenMalformed 204 } else if errors.Is(err, jwt.ErrTokenUnverifiable) { 205 code |= result.TokenUnVerify 206 } else if errors.Is(err, jwt.ErrTokenSignatureInvalid) { 207 code |= result.TokenSigned 208 } else if errors.Is(err, jwt.ErrTokenExpired) || errors.Is(err, jwt.ErrTokenNotValidYet) { 209 // Token is either expired or not active yet 210 code |= result.TokenExpired 211 } else { 212 code |= result.TokenOther 213 } 214 return nil, result.ErrCode(code).WithError(err) 215 } 216 217 type jwtClaims struct { 218 Source token.Source `json:"source"` 219 Session string `json:"session"` 220 Extend string `json:"extend"` 221 Subject string `json:"sub,omitempty"` 222 ExpiresAt *jwt.NumericDate `json:"exp,omitempty"` 223 IssuedAt *jwt.NumericDate `json:"iat,omitempty"` 224 } 225 226 // GetExpirationTime implements the Claims interface. 227 func (tc *jwtClaims) GetExpirationTime() (*jwt.NumericDate, error) { 228 return tc.ExpiresAt, nil 229 } 230 231 // GetNotBefore implements the Claims interface. 232 func (tc *jwtClaims) GetNotBefore() (*jwt.NumericDate, error) { 233 return nil, nil 234 } 235 236 // GetIssuedAt implements the Claims interface. 237 func (tc *jwtClaims) GetIssuedAt() (*jwt.NumericDate, error) { 238 return tc.IssuedAt, nil 239 } 240 241 // GetAudience implements the Claims interface. 242 func (tc *jwtClaims) GetAudience() (jwt.ClaimStrings, error) { 243 return jwt.ClaimStrings{}, nil 244 } 245 246 // GetIssuer implements the Claims interface. 247 func (tc *jwtClaims) GetIssuer() (string, error) { 248 return "", nil 249 } 250 251 // GetSubject implements the Claims interface. 252 func (tc *jwtClaims) GetSubject() (string, error) { 253 return tc.Subject, nil 254 } 255 256 func (tc *jwtClaims) To(tk string) *Token { 257 return &Token{ 258 Session: tc.Session, 259 Uid: tc.Subject, 260 Token: tk, 261 Extend: tc.Extend, 262 Source: tc.Source, 263 expire: timer.Expire{StartIn: tc.IssuedAt.Unix(), ExpireIn: tc.ExpiresAt.Unix()}, 264 } 265 }