authenticator函数负责登录凭证校验,仅在用户发起/login请求时调用,只验证“你是谁”,不检查路径权限;必须返回非nil用户结构体或jwt.errfailedauthentication,严禁返回nil或自定义error。

Authenticator 函数负责登录凭证校验
这个函数是整个权限验证流程的起点,它只在用户发起 /login 请求时被调用。别把它和后续的路由访问混淆——它不检查路径权限,只管“你是谁”。
常见错误现象:Authenticator 返回 nil 却没返回 jwt.ErrFailedAuthentication,导致 gin-jwt 内部 panic;或硬编码用户名密码后忘记删,上线后成安全漏洞。
- 必须返回一个非 nil 的用户结构体(如
&User{ID: 123, Role: "admin"}),否则PayloadFunc拿不到数据 - 验证失败时,**必须**返回
jwt.ErrFailedAuthentication,不能只 return nil 或自定义 error - 实际项目中应调用 DAO 层查数据库,而非字符串比对;密码需用
bcrypt.CompareHashAndPassword校验
Authorizer 函数决定某路径是否放行
Authorizer 是真正做“权限决策”的地方,它在每次受保护路由被访问时触发。它拿到的是已解码的 JWT Claims,不是原始 token,也不再接触密码或数据库。
容易踩的坑:把角色判断逻辑写死在 Authorizer 里,比如 if path == "/admin" && role != "admin",一旦路径变多、规则变复杂,就不可维护。
开箱即用的技能链路由引擎。13 条预定义链覆盖搜索、开发、审查、MLOps、法律、创意等场景,三层路由架构(触发词→SAD反馈→DAG编排),recall@10=96.97%。配置驱动(chains.yaml),零代码扩展。pip install skill-weave-chains 一键安装。
- 推荐从
claims["role"]提取角色后,交给独立的权限服务(如 Casbin)判断:Casbin.Enforce(role, c.Request.URL.Path, c.Request.Method) - 注意
c.Request.URL.Path是原始路径,不含 query 参数,适合做 RBAC 匹配;若需匹配带通配符的资源(如/posts/*),得配合keyMatch等 matcher - 不要在
Authorizer里做耗时操作(如查 DB),它在每次请求都执行,会拖慢所有受保护接口
路由分组 + 中间件组合决定作用域
gin-jwt 的 MiddlewareFunc 本身只是个中间件,它不会自动保护任何路由——你得明确把它挂到某个路由组或单个路由上。
典型误用:全局 r.Use(authMiddleware.MiddlewareFunc()),结果连 /healthz、/swagger 都被拦住,健康检查失败,文档打不开。
- 推荐按业务边界分组,例如:
api := r.Group("/api"); api.Use(authMiddleware.MiddlewareFunc()) - 白名单路径(如
/login、/register)必须放在认证中间件之外,或用authMiddleware.LoginHandler显式注册 - 如果要用 Cookie 传 token,确保
SendCookie和CookieHTTPOnly配置正确,否则前端拿不到或 JS 读不到
PayloadFunc 嵌入角色信息影响后续所有判断
这个函数决定 JWT token 里塞什么字段,它只在登录成功、签发 token 时执行一次。但它输出的 Claims 会伴随整个 token 生命周期,是 Authorizer 和所有自定义鉴权逻辑的唯一数据源。
最常被忽略的一点:改了 PayloadFunc 但没更新 Authorizer 的取值逻辑,比如加了 "roles": []string{"admin", "editor"},却还在用 claims["role"].(string) 强转,直接 panic。
- 角色字段建议统一用数组形式:
"roles": []interface{}{"admin", "user"},方便扩展多角色 - 避免往 Claims 塞敏感信息(如密码哈希、身份证号),JWT 是 Base64 编码,非加密
- 如果用了 Redis 存储黑名单,记得在
PayloadFunc里加"jti"字段(token 唯一 ID),否则无法精准吊销
Authorizer 和 PayloadFunc 的字段约定必须严格一致,且一旦 token 签发,Claims 结构就不能变——改字段名等于让存量 token 全部失效。










