Echo框架JWT Token刷新教程

老雪同学_7193

老雪同学_7193

2026-10-20

669人浏览

原创

Echo v5 中 echo-jwt/v4 不支持自动 Token 刷新,因其仅负责校验 token 合法性,不管理生命周期、不提供刷新接口、不感知用户身份、不修改响应头、不区分 access/refresh token,所有刷新逻辑须手动实现。

echo框架jwt token刷新教程

Echo v5 中没有内置 Token 刷新逻辑,必须自己实现中间件 + 两个 endpoint(/login 和 /refresh),且不能依赖 echo-jwt/v4 自动处理刷新。

为什么 echo-jwt/v4 不支持自动刷新

echo-jwt/v4 的设计目标是「校验」而非「管理生命周期」:它只做一件事——解析并验证 Authorization 头里的 token 是否合法、未过期、签名正确。一旦 err != nil,它直接返回 401 或 400,不会触发任何续签行为。

常见误解是以为配置 SigningKey 后加个回调就能“自动刷新”,但实际:echojwt.Config 里根本没有 RefreshHandler、OnTokenExpired 这类字段;所有刷新动作必须由你手动路由和控制。

  • 它不感知用户身份,无法查数据库或 Redis 获取 refresh token
  • 它不修改响应头,不会自动写入新 Authorization 或 Set-Cookie
  • 它不区分 access token 和 refresh token,传进来什么就验什么

/refresh 接口必须独立实现,且需校验 refresh token

刷新不是“重签一个新 access token”那么简单,关键在安全边界:refresh token 必须比 access token 更长寿命、更严格存储、单次使用或带绑定(如 IP、UA、设备指纹)。

典型流程是:

  • 前端在收到 401 且确认是过期(非非法格式)时,用当前 access token 的 payload 提取 user_id,再带上本地存的 refresh token 请求 /api/v1/refresh
  • 后端验证 refresh token 是否存在、未被撤销、未过期、且与该 user_id 匹配
  • 验证通过后,签发新的 access token(建议短时效,如 15m),并可选地签发新的 refresh token(滚动刷新)
  • 旧 refresh token 应立即失效(例如写入 Redis 黑名单,或更新 DB 中的 refresh_token_hash 字段)

示例片段(不依赖任何框架封装):

Token Watch
Token Watch

跨AI供应商追踪与分析Token用量及成本,支持预算预警、模型成本对比、优化建议及本地数据存储。

下载
e.POST("/api/v1/refresh", func(c echo.Context) error {
    type req struct {
        RefreshToken string `json:"refresh_token"`
    }
    var r req
    if err := c.Bind(&r); err != nil {
        return echo.NewHTTPError(http.StatusBadRequest, "invalid request")
    }
<pre class="brush:php;toolbar:false;">// 1. 解析 refresh token(用独立密钥!别和 access token 共用 SigningKey)
token, err := jwt.Parse(r.RefreshToken, func(t *jwt.Token) (interface{}, error) {
    if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
        return nil, fmt.Errorf("unexpected signing method: %v", t.Header["alg"])
    }
    return []byte("refresh-secret-key"), nil
})
if err != nil || !token.Valid {
    return echo.NewHTTPError(http.StatusUnauthorized, "invalid refresh token")
}

// 2. 检查 payload 中的 user_id 和 jti(唯一标识),查 Redis/DB 确认未撤销
claims, ok := token.Claims.(jwt.MapClaims)
if !ok || !claims.VerifyExpiresAt(time.Now().Unix(), true) {
    return echo.NewHTTPError(http.StatusUnauthorized, "refresh token expired")
}
userID := claims["user_id"].(string)
jti := claims["jti"].(string)
if !isRefreshTokenValid(userID, jti) { // 你自己的校验函数
    return echo.NewHTTPError(http.StatusUnauthorized, "refresh token revoked")
}

// 3. 签发新 access token(HS256,15分钟)
newAccessToken := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
    "user_id": userID,
    "exp":     time.Now().Add(15 * time.Minute).Unix(),
    "iat":     time.Now().Unix(),
})
signedToken, _ := newAccessToken.SignedString([]byte("access-secret-key"))

// 4. 可选:生成新 refresh token 并使旧的失效
newRefreshToken := generateRefreshToken(userID)

return c.JSON(http.StatusOK, map[string]string{
    "access_token":  signedToken,
    "refresh_token": newRefreshToken,
})

})

TokenLookup 和 ErrorHandler 要配合刷新逻辑用

默认 TokenLookup: "header:Authorization" 只会从请求头读,但 /refresh 接口通常需要从 body 或 query 读 refresh token,所以这个接口不能挂 echojwt.WithConfig(...) ——否则还没进你 handler 就被中间件拦下返回 401 了。

同时,ErrorHandler 别只返回 401 文字,要能区分错误类型,方便前端决策:

  • 如果错误是 *jwt.TokenExpiredError,前端才该去调 /refresh
  • 如果是 *jwt.ValidationError(比如签名错、算法不匹配),说明 token 被篡改,必须强制登出
  • 如果是 context.Canceled 或网络超时,不该触发刷新

所以推荐在全局中间件里这样写 ErrorHandler:

ErrorHandler: func(c echo.Context, err error) error {
    var ve *jwt.ValidationError
    if errors.As(err, &ve) {
        if ve.Errors&jwt.ValidationErrorExpired != 0 {
            return c.JSON(http.StatusUnauthorized, map[string]string{
                "error": "token_expired",
                "action": "refresh",
            })
        }
        return c.JSON(http.StatusUnauthorized, map[string]string{
            "error": "token_invalid",
            "action": "logout",
        })
    }
    return c.JSON(http.StatusBadRequest, map[string]string{"error": "malformed_token"})
},

真正难的不是签两个 token,而是 refresh token 的存储、吊销、绑定和轮换策略——这些 echo-jwt/v4 一概不管,得你自己用 Redis 或数据库兜底。漏掉任意一环,刷新机制就变成安全漏洞放大器。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
OpenJDK JVM参数怎么调优
OpenJDK JVM参数怎么调优

Java应用运行缓慢,如何调整JVM参数?本专题介绍OpenJDK JVM性能调优的基本流程,涵盖性能指标确认、运行数据采集、内存配置和垃圾回收分析,帮助你先定位瓶颈,再通过对照测试验证效果,避免直接套用参数而影响应用稳定性。

2026.10.16

60

10

OpenJDK怎么配置Java开发环境
OpenJDK怎么配置Java开发环境

怎样用OpenJDK搭建开发环境?本专题介绍版本选择、下载安装、环境变量配置和编译运行验证,帮助你理清JDK的作用及基本配置流程,并通过简单程序检查环境是否可用,为后续项目开发做好准备。

2026.10.16

40

10

OpenJDK怎么部署Java应用
OpenJDK怎么部署Java应用

Java项目开发完成后,怎样部署到目标环境并正常运行?本专题介绍OpenJDK应用部署流程,涵盖运行环境准备、版本兼容检查、应用打包、启动参数配置和日志查看,帮助你理清部署前后的操作顺序,减少环境差异造成的运行问题。

2026.10.16

40

10

Revel框架模板渲染与表单验证
Revel框架模板渲染与表单验证

本专题围绕Revel框架视图层开发,介绍模板语法、变量输出、布局复用、表单提交、参数绑定与验证规则,帮助开发者完成安全规范的页面交互。

2026.10.16

20

15

Revel框架MVC路由与控制器
Revel框架MVC路由与控制器

本专题聚焦Revel框架MVC核心机制,讲解路由定义、控制器Action、参数绑定、请求响应和反向路由,并结合常见场景梳理接口请求处理流程。

2026.10.16

20

15

Revel框架入门与安装配置
Revel框架入门与安装配置

本专题从Revel框架环境搭建讲起,系统介绍命令行工具安装、项目创建、目录结构、配置文件及热代码重载,帮助开发者快速完成首个Go Web应用。

2026.10.16

20

15

Linux 新手先学哪些命令
Linux 新手先学哪些命令

Linux新手命令专题汇集终端基础、文件目录操作、文本查看、软件安装和权限管理等入门文章,帮助按实际任务练习常用命令并建立命令行操作习惯。

2026.10.15

40

20

MySQL 忘记密码怎么办
MySQL 忘记密码怎么办

MySQL忘记密码专题汇集不同版本与系统下的root密码重置方法,覆盖MySQL 5.7、8.0、Mac、Linux及本地集成环境,并提示恢复权限与重新登录的检查步骤。

2026.10.15

40

18

Vue.js 中 ref 和 reactive 的区别
Vue.js 中 ref 和 reactive 的区别

Vue.js中ref和reactive的区别专题汇集两种响应式API的定义、访问方式、对象解构、侦听与性能取舍等文章,帮助结合实际状态类型选择合适写法。

2026.10.15

20

20

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Minimax手册
Minimax手册

共0课时 | 0人学习

前端Vue3实战【手写vue项目】
前端Vue3实战【手写vue项目】

共9课时 | 1.3万人学习

Echo框架IP地址文档
Echo框架IP地址文档

共0课时 | 0人学习