Go-Zero服务需配置JWT密钥与过期时间、定义Auth配置结构体、编写并挂载鉴权中间件,且仅对标注@server(jwt: Auth)的路由生效。

要在Go-Zero服务中实现用户登录后携带Token访问受保护接口,必须让服务能自动提取并验证JWT签名与有效期,否则每次请求都得手动解析Header、校验exp、比对secret——这不仅重复冗余,还极易漏掉时钟偏移或篡改检测。
配置JWT密钥与过期时间
打开 user-api.yaml(或其他对应API服务的配置文件),在顶层添加 Auth 配置块:
Auth:
AccessSecret: "k9Fq#xR2!vL8mP@n"
AccessExpire: 259200
【AccessSecret必须是8位以上且含大小写字母、数字、特殊字符的强密码】。若仅为"12345678",攻击者可在毫秒级暴力穷举出签名密钥,整个鉴权体系形同虚设。
AccessExpire单位为秒,此处259200即3天,适合多数业务场景;若设为0或负数,token将永不过期,严重违反最小权限原则。
定义配置结构体并加载
在 internal/config/config.go 中,向 Config 结构体追加 Auth 字段:
type Config struct {
rest.RestConf
Auth struct {
AccessSecret string `json:"accessSecret"`
AccessExpire int64 `json:"accessExpire"`
} `json:"auth"`
}
确保 yaml 文件中的字段名(accessSecret/accessExpire)与结构体 tag 完全一致,否则 viper 解析失败,运行时 svcCtx.Config.Auth 为零值,后续签名验证必然 panic。
编写JWT鉴权中间件
在 internal/middleware/authmiddleware.go 中创建新文件,写入以下代码:
func AuthMiddleware() func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authHeader := r.Header.Get("Authorization")
if authHeader == "" {
httpx.Error(w, api.ErrUnauthorized)
return
}
// 提取Bearer后的token字符串
var tokenString string
if strings.HasPrefix(authHeader, "Bearer ") {
tokenString = strings.TrimPrefix(authHeader, "Bearer ")
} else {
httpx.Error(w, api.ErrUnauthorized)
return
}
// 解析并校验token
token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
return []byte(config.Get().Auth.AccessSecret), nil
})
if err != nil || !token.Valid {
httpx.Error(w, api.ErrUnauthorized)
return
}
// 将用户ID注入上下文供后续logic使用
if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid {
if userId, exists := claims["userId"]; exists {
ctx := context.WithValue(r.Context(), "userId", userId)
r = r.WithContext(ctx)
}
}
next.ServeHTTP(w, r)
})
}
}
挂载中间件到路由
找到服务的主入口文件,如 userapi.go,定位到 server := rest.MustNewServer(c) 后的位置:
server.Use(middleware.AuthMiddleware())
这行代码必须放在 server.Start() 之前,且不能写在 handler 注册之后——否则中间件不会生效。若你误将其放在 server.AddRoutes(...) 之后,所有带 Authorization 头的请求仍会绕过鉴权直达业务逻辑。
接着,在 api 定义文件(如 user.api)中,对需要保护的路由显式声明 jwt 标签:
@server(jwt: Auth)
post /user/profile(UserProfileRequest) returns (UserProfileResponse)
【只有打上 @server(jwt: Auth) 的路由才会触发 AuthMiddleware】。未标注的路由(如登录接口本身)将跳过该中间件,避免循环验证。











