字节笔记本
2026年2月22日
go-zero 微服务实战:JWT 鉴权完整指南
本文介绍在 go-zero 微服务框架中实现 JWT 鉴权的完整流程,包括 Token 生成、验证以及从 Token 中获取用户信息等核心操作。
概述
什么是 JWT?
JSON Web 令牌(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑而独立的方法,用于在各方之间安全地将信息作为 JSON 对象传输。由于此信息是经过数字签名的,因此可以被验证和信任。可以使用秘密(使用 HMAC 算法)或使用 RSA 或 ECDSA 的公钥/私钥对对 JWT 进行签名。
什么时候应该使用 JWT?
- 授权:这是使用 JWT 的最常见场景。用户登录后,每个后续请求都将包含 JWT,允许用户访问该令牌允许的路由、服务和资源。单点登录(SSO)是当今广泛使用 JWT 的一项功能,因为它的开销很小,并且能够跨不同域轻松使用。
- 信息交换:JSON Web 令牌是在各方之间安全传输信息的好方法。因为 JWT 可以进行签名(例如,使用公钥/私钥对),所以您可以确定发件人就是他们所说的那个人。此外,由于签名是使用标头和有效负载计算的,因此您还可以验证内容是否未被篡改。
为什么要使用 JSON Web 令牌?
- 简洁:可以通过 URL、POST 参数或 HTTP 标头发送 JWT。由于尺寸小,传输速度快。
- 自包含:有效载荷包含有关用户的所有必需信息,避免了多次查询数据库的需要。
- 安全性:JWT 可以使用 HMAC 算法或 RSA/ECDSA 进行签名,确保信息未被篡改。
如何使用 JWT
JWT 鉴权一般在 API 层使用,本文示例是在用户服务上实现的。
具体步骤:
- 第一步:生成服务 user api
- 第二步:在登录时生成 jwt token
- 第三步:在获取用户信息时验证 jwt token
第一步:生成服务 user api
添加配置定义:
```go // user/api/internal/config/config.go type Config struct { rest.RestConf SecretKey string
Auth struct {
AccessSecret string
AccessExpire int64
}} ```
配置 YAML 配置项:
```yaml
user/api/etc/user-api.yaml
user 模块配置
Name: user-api Host: 0.0.0.0 Port: 9001
SecretKey: C8xHnG6s Auth: AccessSecret: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 AccessExpire: 64800 ```
注意:`AccessSecret` 是生成 jwt token 的密钥,最简单的方式可以使用一个 uuid 值。`AccessExpire` 是 jwt token 有效期,单位:秒。
第二步:在登录时生成 jwt token
生成 Token 的方法:
```go // user/api/internal/logic/login-logic.go func (l *LoginLogic) GetToken(iat int64, secretKey string, payloads map[string]any, seconds int64) (string, error) { claims := make(jwt.MapClaims) claims["expTime"] = iat + seconds claims["iat"] = iat for k, v := range payloads { claims[k] = v }
token := jwt.New(jwt.SigningMethodHS256)
token.Claims = claims
return token.SignedString([]byte(secretKey))} ```
使用示例:
```go payloads := make(map[string]any) payloads["userIdentity"] = userData.UserIdentity
accessToken, tokenErr := l.GetToken(time.Now().Unix(), l.svcCtx.Config.Auth.AccessSecret, payloads, l.svcCtx.Config.Auth.AccessExpire) if tokenErr != nil { return nil, tokenErr } ```
第三步:在获取用户信息时验证 jwt token
编写 user.api 文件:
```go // user/api/user.api type ( UserInfoReq struct{}
UserInfoResply {
Code int64 \`json:"Code"\`
Message string \`json:"Message"\`
Data *UserInfoItem \`json:"Data"\`
}
UserInfoItem {
UserIdentity string \`json:"UserIdentity"\` // 用户唯一标识
UserName string \`json:"UserName"\` // 用户名
UserNick string \`json:"UserNick"\` // 用户昵称
UserFace string \`json:"UserFace"\` // 用户头像地址
UserSex int64 \`json:"UserSex"\` // 用户性别:0男,1女,2保密
UserEmail string \`json:"UserEmail"\` // 用户邮箱
UserPhone string \`json:"UserPhone"\` // 用户手机号
})
@server( jwt: Auth )
service user-api{ @doc ( summary: "用户信息" ) @handler userInfo post /userinfo (UserInfoReq) returns (UserInfoResply) } ```
注意:`jwt: Auth` 表示开启 jwt 鉴权。如果路由需要 jwt 鉴权,则需要在 service 上方声明此语法标志。不需要 jwt 鉴权的路由就无需声明。
获取 jwt token 中携带的信息
go-zero 从 jwt token 解析后会将用户生成 token 时传入的 kv 原封不动的放在 http.Request 的 Context 中,因此我们可以通过 Context 就可以拿到你想要的值。
```go // user/api/internal/logic/user-info-logic.go func (l *UserInfoLogic) UserInfo(req types.UserInfoReq) (resp *types.UserInfoResply, err error) { userIdentity := fmt.Sprintf("%v", l.ctx.Value("userIdentity"))
// 这里的 key 和生成 jwt token 时传入的 key 一致
logx.Infof("userId: %v", userIdentity)
return &types.UserInfoResply{}, nil} ```
结束语
本篇文章介绍说明了在开发过程中会出现的一些情况:
- 什么是 JWT
- 如何生成 JWT Token
- 如何使 JWT Token 生效
另外,如果你感兴趣,非常欢迎你加入,我们一起来完成这个项目,为社区献出自己的一份力。
希望本篇文章对你有所帮助,谢谢。