
本文介绍如何在go语言json-rpc服务中集成jwt进行身份认证与方法级权限控制,包括服务端签发/校验token、rpc方法参数化鉴权、以及仅对特定方法启用授权的实践方案。
本文介绍如何在go语言json-rpc服务中集成jwt进行身份认证与方法级权限控制,包括服务端签发/校验token、rpc方法参数化鉴权、以及仅对特定方法启用授权的实践方案。
在Go语言中构建内部微服务通信层时,JSON-RPC相比HTTP REST具有更低的序列化开销和更紧凑的接口契约,但其原生不支持HTTP中间件或标准认证头(如Authorization: Bearer xxx),因此需在应用层显式设计授权机制。推荐采用JSON Web Token(JWT)作为核心授权方案——它轻量、自包含、可签名防篡改,并天然支持声明式权限(claims),完美适配RPC调用场景。
一、授权流程设计
整个授权链路分为三步:
-
登录认证:客户端调用专用RPC方法(如
Auth.Login),传入API Key / 证书 / 凭据; -
签发JWT:服务端验证凭据后,生成含
service_id、permissions(如["user.read", "order.write"])、exp等声明的Token,并用私钥签名; -
方法级鉴权:受保护方法(如
User.GetProfile)将token string作为首个参数;服务端在方法逻辑前校验Token有效性及所需权限。
二、关键代码实现
首先引入JWT库(推荐维护更活跃的 github.com/golang-jwt/jwt/v5):
go get github.com/golang-jwt/jwt/v5
1. JWT签发与校验工具封装
// auth/jwt.go
var (
jwtKey = []byte("your-32-byte-secret-key-here") // 生产环境请使用环境变量或密钥管理服务
)
func GenerateToken(serviceID string, permissions []string) (string, error) {
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"service_id": serviceID,
"permissions": permissions,
"exp": time.Now().Add(24 * time.Hour).Unix(),
"iat": time.Now().Unix(),
})
return token.SignedString(jwtKey)
}
func ValidateToken(tokenStr string, requiredPerm string) (map[string]interface{}, error) {
token, err := jwt.Parse(tokenStr, 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 jwtKey, nil
})
if err != nil {
return nil, err
}
if !token.Valid {
return nil, errors.New("invalid token")
}
claims, ok := token.Claims.(jwt.MapClaims)
if !ok {
return nil, errors.New("invalid token claims")
}
perms, ok := claims["permissions"].([]interface{})
if !ok {
return nil, errors.New("missing permissions claim")
}
for _, p := range perms {
if p == requiredPerm {
return claims, nil
}
}
return nil, fmt.Errorf("permission denied: %s", requiredPerm)
}
2. RPC服务注册与鉴权拦截
// rpc/server.go
type AuthService struct{}
type UserService struct{}
func (a *AuthService) Login(r *http.Request, args *struct {
APIKey string `json:"api_key"`
}, reply *struct {
Token string `json:"token"`
}) error {
// 实际应查数据库或配置中心校验API Key
if args.APIKey != "valid-service-key" {
return errors.New("invalid api key")
}
token, err := auth.GenerateToken("payment-service", []string{"user.read", "order.write"})
if err != nil {
return err
}
*reply = struct{ Token string }{Token: token}
return nil
}
func (u *UserService) GetProfile(r *http.Request, args *struct {
Token string `json:"token"`
UserID int `json:"user_id"`
}, reply *struct {
Name string `json:"name"`
}) error {
// 关键:方法内校验权限
_, err := auth.ValidateToken(args.Token, "user.read")
if err != nil {
return fmt.Errorf("authorization failed: %w", err)
}
// 正常业务逻辑
*reply = struct{ Name string }{Name: "Alice"}
return nil
}
// 启动RPC服务器
func main() {
rpc.Register(&AuthService{})
rpc.Register(&UserService{}) // 仅此方法需鉴权,其他方法(如Health.Check)可不校验
rpc.HandleHTTP()
http.ListenAndServe(":8080", nil)
}
三、注意事项与最佳实践
- ✅ 权限最小化:为每个调用方分配专属Token,且
permissions字段仅包含必需能力(如["inventory.read"]而非["*"]); - ✅ Token安全传输:RPC请求体中的Token需通过TLS加密通道传输,禁止明文日志记录Token;
- ✅ 方法粒度控制:无需全局拦截——仅在敏感方法的参数中显式接收
token,保持非敏感方法(如Ping、Version)无侵入; - ⚠️ 密钥管理:生产环境严禁硬编码
jwtKey,应使用KMS(如AWS KMS、HashiCorp Vault)动态获取; - ⚠️ 时效性:设置合理
exp(建议≤24h),并配合短期Token+刷新机制应对长期会话需求。
通过上述方案,你可在Go JSON-RPC服务中实现安全、灵活、可审计的授权体系,既满足内部服务间可信调用需求,又避免过度设计复杂网关层。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











