# 6.4 JWT
# 6.4.1 第三方库
- github.com/dobyte/jwt@v0.1.4 (opens new window)
- github.com/go-redis/redis/v8@v8.11.5 (opens new window)
# 6.4.2 配置参数
| 名称 | 类型 | 描述 |
|---|---|---|
issuer | string | jwt发行方 |
validDuration | int | 过期时间(秒),默认7200s |
secretKey | string | 秘钥KEY |
identityKey | string | 身份认证KEY |
locations | string | token查找位置 |
store | object | token存储配置 |
store.addrs | string | 连接地址 |
store.db | int | 数据库号,默认为0 |
store.username | string | 用户名,默认空 |
store.password | string | 密码,默认空 |
store.keyFile | string | 私钥文件,默认空 |
store.certFile | string | 证书文件,默认空 |
store.caFile | string | CA证书文件,默认空 |
store.maxRetries | int | 网络相关的错误最大重试次数,默认3次 |
store.poolSize | int | 最大连接池限制,默认为200个连接 |
store.minIdleConns | int | 最小空闲连接数,默认10个连接 |
store.dialTimeout | string | 拨号超时时间,支持单位:纳秒(ns)、微秒(us 或 µs)、毫秒(ms)、秒(s)、分(m)、小时(h)、天(d)。默认为5s |
store.idleTimeout | string | 连接最大空闲时间,支持单位:纳秒(ns)、微秒(us 或 µs)、毫秒(ms)、秒(s)、分(m)、小时(h)、天(d)。默认0s |
store.readTimeout | string | 读超时,支持单位:纳秒(ns)、微秒(us 或 µs)、毫秒(ms)、秒(s)、分(m)、小时(h)、天(d)。默认1s |
store.writeTimeout | string | 写超时,支持单位:纳秒(ns)、微秒(us 或 µs)、毫秒(ms)、秒(s)、分(m)、小时(h)、天(d)。默认1s |
# 6.4.3 示例代码
以下完整示例详见:third-jwt-example (opens new window)
- 组件封装
文件位置:third-jwt-example/jwt/jwt.go (opens new window)
package jwt
import (
"fmt"
"github.com/dobyte/due/v2/core/pool"
"github.com/dobyte/due/v2/etc"
"github.com/dobyte/due/v2/log"
"github.com/dobyte/jwt"
)
var factory = pool.NewFactory(func(name string) (*JWT, error) {
return NewInstance(fmt.Sprintf("etc.jwt.%s", name))
})
type (
JWT = jwt.JWT
Token = jwt.Token
Payload = jwt.Payload
)
type Config struct {
Issuer string `json:"issuer"`
SecretKey string `json:"secretKey"`
IdentityKey string `json:"identityKey"`
Locations string `json:"locations"`
ValidDuration int `json:"validDuration"`
Store *StoreConfig `json:"store"`
}
// Instance JWT实例
func Instance(name ...string) *JWT {
var (
err error
ins *JWT
)
if len(name) == 0 {
ins, err = factory.Get("default")
} else {
ins, err = factory.Get(name[0])
}
if err != nil {
log.Fatalf("create jwt instance failed: %v", err)
}
return ins
}
// NewInstance 创建实例
func NewInstance[T string | Config | *Config](config T) (*JWT, error) {
var (
conf *Config
v any = config
)
switch c := v.(type) {
case string:
conf = &Config{
Issuer: etc.Get(fmt.Sprintf("%s.issuer", c)).String(),
SecretKey: etc.Get(fmt.Sprintf("%s.secretKey", c)).String(),
IdentityKey: etc.Get(fmt.Sprintf("%s.identityKey", c)).String(),
Locations: etc.Get(fmt.Sprintf("%s.locations", c)).String(),
ValidDuration: etc.Get(fmt.Sprintf("%s.validDuration", c)).Int(),
}
if etc.Has(fmt.Sprintf("%s.store", c)) {
conf.Store = &StoreConfig{
Addrs: etc.Get(fmt.Sprintf("%s.store.addrs", c)).Strings(),
DB: etc.Get(fmt.Sprintf("%s.store.db", c)).Int(),
CertFile: etc.Get(fmt.Sprintf("%s.store.certFile", c)).String(),
KeyFile: etc.Get(fmt.Sprintf("%s.store.keyFile", c)).String(),
CaFile: etc.Get(fmt.Sprintf("%s.store.caFile", c)).String(),
Username: etc.Get(fmt.Sprintf("%s.store.username", c)).String(),
Password: etc.Get(fmt.Sprintf("%s.store.password", c)).String(),
MaxRetries: etc.Get(fmt.Sprintf("%s.store.maxRetries", c), 3).Int(),
PoolSize: etc.Get(fmt.Sprintf("%s.store.poolSize", c), 200).Int(),
MinIdleConns: etc.Get(fmt.Sprintf("%s.store.minIdleConns", c), 20).Int(),
DialTimeout: etc.Get(fmt.Sprintf("%s.store.dialTimeout", c), "3s").Duration(),
IdleTimeout: etc.Get(fmt.Sprintf("%s.store.idleTimeout", c)).Duration(),
ReadTimeout: etc.Get(fmt.Sprintf("%s.store.readTimeout", c), "1s").Duration(),
WriteTimeout: etc.Get(fmt.Sprintf("%s.store.writeTimeout", c), "1s").Duration(),
}
}
case Config:
conf = &c
case *Config:
conf = c
}
opts := make([]jwt.Option, 0, 6)
opts = append(opts, jwt.WithIssuer(conf.Issuer))
opts = append(opts, jwt.WithIdentityKey(conf.IdentityKey))
opts = append(opts, jwt.WithSecretKey(conf.SecretKey))
opts = append(opts, jwt.WithValidDuration(conf.ValidDuration))
opts = append(opts, jwt.WithLookupLocations(conf.Locations))
if conf.Store != nil {
store, err := NewStore(conf.Store)
if err != nil {
return nil, err
}
opts = append(opts, jwt.WithStore(store))
}
return jwt.NewJWT(opts...)
}
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
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
文件位置:third-jwt-example/jwt/store.go (opens new window)
package jwt
import (
"context"
"time"
"github.com/dobyte/due/v2/core/tls"
"github.com/dobyte/due/v2/utils/xconv"
"github.com/go-redis/redis/v8"
)
type StoreConfig struct {
Addrs []string `json:"addrs"`
DB int `json:"db"`
Username string `json:"username"`
Password string `json:"password"`
CertFile string `json:"certFile"`
KeyFile string `json:"keyFile"`
CaFile string `json:"caFile"`
MaxRetries int `json:"maxRetries"`
PoolSize int `json:"poolSize"`
MinIdleConns int `json:"minIdleConns"`
IdleTimeout time.Duration `json:"idleTimeout"`
DialTimeout time.Duration `json:"dialTimeout"`
ReadTimeout time.Duration `json:"readTimeout"`
WriteTimeout time.Duration `json:"writeTimeout"`
}
type Store struct {
redis redis.UniversalClient
}
func NewStore(conf *StoreConfig) (*Store, error) {
options := &redis.UniversalOptions{
Addrs: conf.Addrs,
DB: conf.DB,
Username: conf.Username,
Password: conf.Password,
MaxRetries: conf.MaxRetries,
PoolSize: conf.PoolSize,
MinIdleConns: conf.MinIdleConns,
IdleTimeout: conf.IdleTimeout,
DialTimeout: conf.DialTimeout,
ReadTimeout: conf.ReadTimeout,
WriteTimeout: conf.WriteTimeout,
}
if conf.CertFile != "" && conf.KeyFile != "" && conf.CaFile != "" {
if tlsConfig, err := tls.MakeRedisTLSConfig(conf.CertFile, conf.KeyFile, conf.CaFile); err != nil {
return nil, err
} else {
options.TLSConfig = tlsConfig
}
}
return &Store{redis: redis.NewUniversalClient(options)}, nil
}
func (s *Store) Get(ctx context.Context, key any) (any, error) {
return s.redis.Get(ctx, xconv.String(key)).Result()
}
func (s *Store) Set(ctx context.Context, key any, value any, duration time.Duration) error {
return s.redis.Set(ctx, xconv.String(key), value, duration).Err()
}
func (s *Store) Remove(ctx context.Context, keys ...any) (value any, err error) {
list := make([]string, 0, len(keys))
for _, key := range keys {
list = append(list, xconv.String(key))
}
return s.redis.Del(ctx, list...).Result()
}
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
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
- 配置示例
文件位置:third-jwt-example/etc/etc.toml (opens new window)
[jwt.default]
# jwt发行方
issuer = "due"
# 过期时间
validDuration = 7200
# 秘钥KEY
secretKey = "xxxx"
# 身份认证KEY
identityKey = "uid"
# TOKEN查找位置
locations = "query:token,header:Authorization"
# 存储组件
[jwt.default.store]
# 连接地址
addrs = ["127.0.0.1:6379"]
# 数据库号,默认为0
db = 0
# 用户名,默认空
username = ""
# 密码,默认空
password = ""
# 私钥文件
keyFile = ""
# 证书文件
certFile = ""
# CA证书文件
caFile = ""
# 网络相关的错误最大重试次数,默认3次
maxRetries = 3
# 最大连接池限制,默认为200个连接
poolSize = 200
# 最小空闲连接数,默认10个连接
minIdleConns = 10
# 拨号超时时间,支持单位:纳秒(ns)、微秒(us | µs)、毫秒(ms)、秒(s)、分(m)、小时(h)、天(d)。默认5s
dialTimeout = "5s"
# 连接最大空闲时间,支持单位:纳秒(ns)、微秒(us | µs)、毫秒(ms)、秒(s)、分(m)、小时(h)、天(d)。默认0s
idleTimeout = "0s"
# 读超时,支持单位:纳秒(ns)、微秒(us | µs)、毫秒(ms)、秒(s)、分(m)、小时(h)、天(d)。默认1s
readTimeout = "1s"
# 写超时,支持单位:纳秒(ns)、微秒(us | µs)、毫秒(ms)、秒(s)、分(m)、小时(h)、天(d)。默认1s
writeTimeout = "1s"
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
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
- 组件调用
文件位置:third-jwt-example/main.go (opens new window)
package main
import (
"third-jwt-example/jwt"
"github.com/dobyte/due/v2/log"
)
func main() {
ins := jwt.Instance("default")
token, err := ins.GenerateToken(jwt.Payload{
ins.IdentityKey(): 1,
"nickname": "fuxiao",
})
if err != nil {
log.Errorf("generate token error: %v", err)
} else {
log.Infof("generate token success: %s", token.Token)
}
payload, err := ins.ExtractPayload(token.Token)
if err != nil {
log.Errorf("extract payload error: %v", err)
} else {
log.Infof("extract payload success: %v", payload)
}
}
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
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
← 6.3 Mongo 6.5 Casbin →