JWT校验总报token is expired但实际没过期,最常见原因是网关服务器本地时间未同步,导致time.Now().Unix()与exp时间戳偏差超限;解决方法是用jwt.WithValidator注入±1.5秒容错逻辑,并强制ntpdate或chronyc makestep校时。

JWT校验为什么总报token is expired但实际没过期
网关服务器本地时间未同步,是jwt.ParseWithClaims报token is expired最常见原因。JWT的exp字段是Unix时间戳,校验时直接比对time.Now().Unix(),系统时间偏差超过1秒就会失败——而systemd-timesyncd默认5分钟同步一次,压测或容器重启后极易脱节。
解决方法不是调大NTP轮询频率,而是从校验逻辑层容忍偏差:
- 用
jwt.WithValidator注入自定义时间检查,允许±1.5秒误差,例如:jwt.WithValidator(func(t time.Time) bool { return t.After(time.Now().Add(-1.5 * time.Second)) && t.Before(time.Now().Add(1.5 * time.Second)) }) - 部署脚本里强制加一行
ntpdate -s time.windows.com或chronyc -a makestep - 别依赖
Parse忽略claims类型,必须用ParseWithClaims(&MyClaims{}),否则exp字段可能被当字符串解析
Kong Go插件里如何安全获取和设置HTTP头
Kong Go插件不是独立HTTP服务,所有上下文必须走PDK(Plugin Development Kit),不能碰原始http.Request或http.ResponseWriter。直接调用r.Header.Get("Authorization")或w.Header().Set("X-Auth-By", "go-jwt")会导致请求上下文丢失、日志不完整、超时机制失效。
正确做法是:
立即学习“go语言免费学习笔记(深入)”;
- 取Header:用
pdk.request.get_header("Authorization"),返回string或nil,注意判空 - 设响应头:用
pdk.response.set_header("X-Auth-By", "go-jwt"),不是Header().Set() - 终止流程:鉴权失败必须调
pdk.response.exit(401, map[string]interface{}{"error": "invalid_token"}),禁用panic、os.Exit或裸return - 提取token时记得
strings.TrimSpace并切掉"Bearer "前缀,否则ParseWithClaims会报square/go-jose: error in cryptographic primitive
为什么不能手写JWT中间件而要复用golang-jwt/jwt/v5
自己用jwt.Parse+http.Handler搭鉴权中间件,短期能跑,但长期会暴露密钥轮换难、token刷新缺失、错误响应格式不统一、无旁路缓存导致Redis击穿等硬伤。
复用github.com/golang-jwt/jwt/v5的核心价值在于结构化校验流程:
- 必须调
VerifyExpiresAt和VerifyNotBefore,不能只读claims.Exp字段——后者不校验时钟偏差,也不触发Valid标记 - 签发时用
WithIssuer/WithSubject明确上下文,避免下游服务自行解析出错 - 校验失败统一返回
401 Unauthorized+{"error": "invalid_token"},Kong后续插件依赖这个body格式做透传 - 黑名单校验别每次查Redis,用
sync.Map缓存最近10分钟失效的jti,TTL设为600秒
Go插件编译失败提示plugin not found or invalid怎么办
Kong加载Go插件失败,90%是因为编译参数不对。Kong的Go插件本质是通过Unix socket + Protobuf与Lua主进程通信,不是普通可执行文件。
关键编译命令必须满足三项:
-
CGO_ENABLED=0:禁用Cgo,否则动态链接库在容器里找不到 -
go build -buildmode=plugin:生成.so文件,不是main包可执行文件 -
-o auth.so ./plugin.go:输出名必须带.so后缀,且文件路径需在Kong配置的plugins_dir下
插件入口函数签名必须是func New() interface{},返回实现kong.PluginInterface的struct;任何init()里启动goroutine或监听端口的操作,都会让Kong控制流断裂。


















