-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathclaims.go
112 lines (100 loc) · 2.93 KB
/
claims.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
package jwt
import (
"encoding/json"
"fmt"
)
// IClaims https://datatracker.ietf.org/doc/html/rfc7519#section-4.1 namely
// {exp, iat, nbf, iss, sub, aud}
// 之所以提供這個方法,只是為了在驗證的時候,可以避免用map打key的方式
// 另外因為驗證的時後claims我們能得到的資訊只有字串,所以這邊的工作還要負責把字串轉換成合適的型別
type IClaims interface {
GetExpirationTime() (*NumericDate, error)
GetIssuedAt() (*NumericDate, error)
GetNotBefore() (*NumericDate, error)
GetIssuer() (string, error)
GetSubject() (string, error)
GetAudience() (ClaimStrings, error)
}
type MapClaims map[string]any
// GetExpirationTime implements the Claims interface.
func (m MapClaims) GetExpirationTime() (*NumericDate, error) {
return m.parseNumericDate("exp")
}
// GetNotBefore implements the Claims interface.
func (m MapClaims) GetNotBefore() (*NumericDate, error) {
return m.parseNumericDate("nbf")
}
// GetIssuedAt implements the Claims interface.
func (m MapClaims) GetIssuedAt() (*NumericDate, error) {
return m.parseNumericDate("iat")
}
// GetAudience implements the Claims interface.
func (m MapClaims) GetAudience() (ClaimStrings, error) {
return m.parseClaimsString("aud")
}
// GetIssuer implements the Claims interface.
func (m MapClaims) GetIssuer() (string, error) {
return m.parseString("iss")
}
// GetSubject implements the Claims interface.
func (m MapClaims) GetSubject() (string, error) {
return m.parseString("sub")
}
// 轉成日期, 如果key值沒有提供不算錯誤
func (m MapClaims) parseNumericDate(key string) (*NumericDate, error) {
v, ok := m["exp"]
if !ok {
return nil, nil // 不算錯,因為有可能此欄位非必須,是否會錯交由外層判斷
}
switch exp := v.(type) {
case float64:
if exp == 0 {
return nil, nil
}
return newNumericDateFromSeconds(exp), nil
case json.Number:
f64, err := exp.Float64()
if err != nil {
return nil, err
}
return newNumericDateFromSeconds(f64), nil
}
return nil, fmt.Errorf("%s is invalid %w", key, ErrInvalidType)
}
// parseClaimsString tries to parse a key in the map claims type as a
// [ClaimsStrings] type, which can either be a string or an array of string.
func (m MapClaims) parseClaimsString(key string) (ClaimStrings, error) {
var cs []string
switch v := m[key].(type) {
case string:
cs = append(cs, v)
case []string:
cs = v
case []interface{}:
for _, a := range v {
vs, ok := a.(string)
if !ok {
return nil, fmt.Errorf("%s is invalid. %w", key, ErrInvalidType)
}
cs = append(cs, vs)
}
}
return cs, nil
}
// parseString 如果key沒有提供,不算錯誤,是否錯誤將由後續自行決定
func (m MapClaims) parseString(key string) (string, error) {
var (
ok bool
raw interface{}
iss string
)
raw, ok = m[key]
if !ok {
return "", nil
}
iss, ok = raw.(string)
if !ok {
return "", fmt.Errorf("%s is invalid. %w", key, ErrInvalidType)
}
return iss, nil
}