Go语言gRPC如何向代理服务器传递Basic Auth等请求头
Go 语言 gRPC 传递请求头实现前置Nginx鉴权方案
gRPC 不直接支持HTTP/1.1风格的常规请求头传递,鉴权凭证需要通过gRPC原生的**Metadata(元数据)**机制传输,Nginx的gRPC代理模块可自动识别Metadata键值并映射为HTTP请求头,完全满足前置代理校验凭证后转发的需求。
方案一:全局注入固定凭证(推荐,适配固定鉴权场景)
该方案会在连接维度配置所有RPC请求自动携带鉴权头,无需每次调用重复编写传参逻辑。
- 首先自定义RPC凭证实现,对接gRPC的PerRPCCredentials接口:
import ( "context" "google.golang.org/grpc/credentials" "google.golang.org/grpc/metadata" ) // NginxAuthCreds 前置Nginx代理鉴权凭证 type NginxAuthCreds struct { Authorization string // Basic认证凭证 APIKey string // API Key } // GetRequestMetadata 每次RPC调用自动触发,返回需要携带的元数据(自动映射为Nginx可识别的请求头) func (c *NginxAuthCreds) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) { return map[string]string{ "authorization": c.Authorization, "apikey": c.APIKey, }, nil } // RequireTransportSecurity 明文insecure连接返回false,启用TLS时需改为true func (c *NginxAuthCreds) RequireTransportSecurity() bool { return false }
- 修改原有gRPC连接初始化代码,注入全局凭证:
// 初始化鉴权配置,填入你实际的凭证值 authCreds := &NginxAuthCreds{ Authorization: "Basic dXNlcjE6dGVzdDE=", APIKey: "user1", } conn, err := grpc.Dial( "127.0.0.1:"+gRPCserver_port, grpc.WithTransportCredentials(insecure.NewCredentials()), // 注入全局认证凭证,该连接所有请求自动携带鉴权头 grpc.WithPerRPCCredentials(authCreds), ) if err != nil { log.Fatalf("can not connect with server %v", err) }
方案二:单请求自定义传递请求头
如果需要给特定请求单独传递头,不需要全局配置,可以在调用RPC前将Metadata注入上下文即可:
// 构造要传递的请求头键值对 md := metadata.New(map[string]string{ "authorization": "Basic dXNlcjE6dGVzdDE=", "apikey": "user1", }) // 将元数据绑定到上下文 ctx := metadata.NewOutgoingContext(context.Background(), md) // 发起RPC调用时传入该上下文即可生效,示例为调用Admin接口 resp, err := client.Admin(ctx, &pb.AdminRequest{})
注意事项
- gRPC Metadata的键会自动做小写规范化,Nginx侧读取请求头时不区分大小写,无需特意配置大写开头的键名,即可被原有鉴权规则正常识别
- 无需手动传递
content-type请求头,gRPC框架会自动设置标准gRPC请求类型,Nginx代理gRPC流量时不会校验REST场景下的application/json类型要求 - 若后续为gRPC连接启用TLS加密,需要将
RequireTransportSecurity方法的返回值改为true,否则凭证注入逻辑会失效
内容的提问来源于stack exchange,提问作者ELIPHOSIF IDHAI
相关产品推荐
相关产品推荐

