gRPC服务端必须启用TLS,否则JWT认证无效;需用ServerTLSFromFile加载证书,客户端用ClientTLSFromFile并校验域名;AuthInterceptor统一校验JWT,禁用HS256;PerRPCCredentials自动携带token;mTLS是服务间认证基线,需双向验证与证书轮换机制。

gRPC服务端必须启用TLS,否则JWT认证形同虚设
不启用TLS就传JWT,相当于把密码写在明信片上寄出去——authorization header 会被中间人直接截获复用。gRPC 的 metadata 在 HTTP/2 层透传,但本身不加密;没 TLS,所有认证信息都裸奔。
- 服务端必须用
credentials.NewServerTLSFromFile("server.crt", "server.key")加载证书,不能用grpc.WithInsecure() - 客户端连接时,必须用
credentials.NewClientTLSFromFile("ca.crt", "your-service.example"),其中域名要和证书CN或SAN匹配,否则校验失败 - 开发阶段若用自签名证书,客户端别跳过验证(即不要设
RequireTransportSecurity()=false),而应加载 CA 证书池:credentials.NewClientTLSFromCert(pool, "")
用 UnaryInterceptor 统一校验 JWT,但别在每个方法里重复写
把 token 解析、签名校验、过期检查、iss/aud 校验全塞进每个 RPC 方法里,既难维护又容易漏逻辑。正确做法是写一个 AuthInterceptor,用 grpc.UnaryInterceptor 注册到 server。
- 拦截器里用
metadata.FromIncomingContext(ctx)提取authorization,注意 key 是小写,且值格式为"Bearer xxx" - 校验必须用 RS256/ES256,禁止 HS256:私钥只存于授权中心,服务端只加载公钥(
*rsa.PublicKey),避免密钥泄露风险 - 失败时统一返回
status.Error(codes.Unauthenticated, "invalid token"),不要暴露是 exp 过期还是 aud 不匹配——防止信息泄露
PerRPCCredentials 比手动 AppendToOutgoingContext 更可靠
有人喜欢在每次调用前用 metadata.AppendToOutgoingContext(ctx, "authorization", "Bearer "+token),这看似简单,但极易遗漏或错放在错误的 context 上(比如用了 background context 而非带 timeout 的)。更健壮的方式是实现 credentials.PerRPCCredentials 接口。
- 结构体只需实现两个方法:
GetRequestMetadata()返回 map[string]string,RequireTransportSecurity()必须返回true - 初始化 client 时直接传
grpc.WithPerRPCCredentials(&auth{token: tokenStr}),后续所有 RPC 自动携带,无需每处手动构造 context - 如果 token 需刷新(如短期 JWT),可在此结构体中加锁 + 延迟加载逻辑,比在业务层轮询续期更集中可控
mTLS 不是“锦上添花”,而是服务间通信的基线要求
只靠 JWT 不足以证明“你是谁”,只能证明“你持有某个 token”;而 mTLS 才能确认“你确实是 service-a.prod.svc.cluster.local”。尤其在 Kubernetes 内部服务调用场景下,mTLS 是零信任架构的起点。
立即学习“go语言免费学习笔记(深入)”;
- 服务端开启双向认证需设置
ClientAuth: tls.RequireAndVerifyClientCert,并用loadCA()加载客户端根证书池 - 客户端连接时,除了服务端 CA,还需提供自己的证书+私钥:
credentials.NewClientTLSFromFile("ca.crt", "")不够,得用credentials.NewTLS(&tls.Config{...})显式配置Certificates - 务必检查
req.TLS.PeerCertificates是否非空且长度 > 0,这是 mTLS 成功建立的唯一可信信号,不能只依赖 metadata 中的 token
真正棘手的不是“怎么写认证代码”,而是如何让 TLS 证书轮换、JWT 公钥更新、mTLS 客户端证书吊销这些运维动作不中断服务——它们往往在深夜生效,而你的拦截器可能正拿着过期公钥校验新 token。










