JWT

第三方库

配置参数

名称类型描述
issuerstringjwt 发行方
validDurationint过期时间(秒),默认 7200s
secretKeystring秘钥 KEY
identityKeystring身份认证 KEY
locationsstringtoken 查找位置
storeobjecttoken 存储配置
store.addrsstring连接地址
store.dbint数据库号,默认为 0
store.usernamestring用户名,默认空
store.passwordstring密码,默认空
store.keyFilestring私钥文件,默认空
store.certFilestring证书文件,默认空
store.caFilestringCA 证书文件,默认空
store.maxRetriesint网络相关的错误最大重试次数,默认 3 次
store.poolSizeint最大连接池限制,默认为 200 个连接
store.minIdleConnsint最小空闲连接数,默认 10 个连接
store.dialTimeoutstring拨号超时时间,支持单位:纳秒(ns)、微秒(us 或 µs)、毫秒(ms)、秒(s)、分(m)、小时(h)、天(d)。默认为 5s
store.idleTimeoutstring连接最大空闲时间,支持单位:纳秒(ns)、微秒(us 或 µs)、毫秒(ms)、秒(s)、分(m)、小时(h)、天(d)。默认 0s
store.readTimeoutstring读超时,支持单位:纳秒(ns)、微秒(us 或 µs)、毫秒(ms)、秒(s)、分(m)、小时(h)、天(d)。默认 1s
store.writeTimeoutstring写超时,支持单位:纳秒(ns)、微秒(us 或 µs)、毫秒(ms)、秒(s)、分(m)、小时(h)、天(d)。默认 1s

示例代码

以下完整示例详见: third-jwt-example

  1. 组件封装

文件位置: third-jwt-example/jwt/jwt.go

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...)
}

文件位置: third-jwt-example/jwt/store.go

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. 配置示例

文件位置: third-jwt-example/etc/etc.toml

[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. 组件调用

文件位置: third-jwt-example/main.go

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)
	}
}