2. gRPC 核心概念回顾:Protocol Buffers、Service定义与四种通信模式
在深入权限验证之前,必须牢固掌握 gRPC 的基础构件。本章将系统回顾 Protocol Buffers 序列化协议、Service 定义规范,以及四种 RPC 通信模式。这些概念是后续实现拦截器、Token 校验和 RBAC 策略的基石。
2.1 Protocol Buffers:接口定义语言与序列化引擎
Protocol Buffers(简称 Protobuf)是 gRPC 默认的接口定义语言(IDL)和序列化工具。它使用 .proto 文件定义数据结构和服务接口,生成各语言的高效代码。
| 特性 | 说明 | 与权限验证的关联 |
|---|---|---|
| 强类型定义 | 每个字段有明确类型(int32, string, enum, message) | 确保权限上下文字段(如 user_id, role)类型安全 |
| 向后兼容 | 字段编号(field number)机制支持新增/废弃字段 | 权限元数据扩展时无需破坏现有客户端 |
| 二进制编码 | 序列化后体积小、速度快 | Token 和凭证在传输中开销极低 |
| 多语言生成 | 通过 protoc 编译器生成 Java/Go/Python/C++ 等代码 | 权限策略可在异构微服务间统一执行 |
关键实践:在
.proto 文件中,将权限相关的元数据定义在独立的 message 中,例如 AuthContext,便于在拦截器中统一解析。
2.2 Service 定义:RPC 方法的契约
在 .proto 文件中,使用 service 关键字声明一组 RPC 方法。每个方法指定输入消息和输出消息,形成服务端与客户端的严格契约。
syntax = "proto3";
package authz.example;
// 权限上下文消息
message AuthContext {
string user_id = 1;
string role = 2; // admin, editor, viewer
string access_token = 3;
}
// 文档请求
message DocumentRequest {
string document_id = 1;
AuthContext auth = 2; // 内嵌权限上下文
}
// 文档响应
message DocumentResponse {
string content = 1;
int32 status_code = 2;
}
// 文档服务定义
service DocumentService {
// 一元 RPC:获取单个文档
rpc GetDocument(DocumentRequest) returns (DocumentResponse);
// 服务端流式 RPC:获取文档版本历史
rpc StreamDocumentHistory(DocumentRequest) returns (stream DocumentResponse);
// 客户端流式 RPC:批量上传文档
rpc BatchUploadDocument(stream DocumentRequest) returns (DocumentResponse);
// 双向流式 RPC:实时协作编辑
rpc CollaborativeEdit(stream DocumentRequest) returns (stream DocumentResponse);
}
权限设计提示:将
AuthContext 作为每个请求消息的公共字段,而不是单独放在 metadata 中,可以确保权限数据在流式场景下始终与请求绑定,避免上下文丢失。
2.3 四种通信模式详解
gRPC 基于 HTTP/2 支持四种 RPC 模式,每种模式对权限验证的时机和粒度有不同影响。
2.3.1 Unary RPC(一元模式)
客户端发送单个请求,服务端返回单个响应。这是最基础的请求-响应模式,权限验证在服务端收到完整请求后、业务逻辑执行前完成。
- 验证时机:请求到达后立即校验 Token 和角色。
- 适用场景:查询单个资源、执行单一操作。
- 权限粒度:方法级 + 资源级。
2.3.2 Server Streaming RPC(服务端流式模式)
客户端发送单个请求,服务端返回一个消息流。权限验证在流开始前执行一次,后续所有流消息共享该验证结果。
- 验证时机:仅在流建立时校验一次。
- 适用场景:日志推送、数据导出、实时通知。
- 权限粒度:方法级 + 流级(整个流共享权限上下文)。
2.3.3 Client Streaming RPC(客户端流式模式)
客户端发送一个消息流,服务端在接收完所有消息后返回单个响应。权限验证可以在流开始时校验,也可以在每条消息到达时增量校验。
- 验证时机:流开始时做基础校验;每条消息可做增量校验(如检查数据归属)。
- 适用场景:批量上传、传感器数据采集。
- 权限粒度:方法级 + 消息级(每条消息可携带独立权限上下文)。
2.3.4 Bidirectional Streaming RPC(双向流式模式)
客户端和服务端同时发送和接收消息流,两者独立且异步。权限验证需要在连接建立时执行,并在整个流生命周期内维护会话状态。
- 验证时机:流建立时做初始校验;后续每条消息可携带增量 Token 或刷新凭证。
- 适用场景:实时聊天、协作编辑、游戏状态同步。
- 权限粒度:连接级 + 消息级(支持动态权限变更)。
流式权限陷阱:在双向流模式中,如果只在连接建立时校验一次,后续消息可能来自权限已变更的客户端。建议在每条消息中携带轻量级 Token 或使用 gRPC 拦截器定期重新验证。
2.4 四种模式与权限验证对比
| 模式 | 请求/响应数量 | 验证时机 | 权限粒度 | 典型场景 |
|---|---|---|---|---|
| Unary | 1 请求 → 1 响应 | 请求到达时 | 方法级 + 资源级 | 获取用户信息、创建订单 |
| Server Streaming | 1 请求 → N 响应 | 流建立时 | 方法级 + 流级 | 日志推送、数据导出 |
| Client Streaming | N 请求 → 1 响应 | 流开始时 + 可选消息级 | 方法级 + 消息级 | 批量上传、数据采集 |
| Bidirectional Streaming | N 请求 ↔ N 响应 | 流建立时 + 消息级 | 连接级 + 消息级 | 实时聊天、协作编辑 |
2.5 四种通信模式架构图
下图展示了四种 RPC 模式在客户端与服务端之间的消息流向,以及权限验证的介入点。
2.6 流式模式下的权限上下文传递
在流式 RPC 中,权限上下文不能仅依赖连接建立时的单次校验。下图展示了在双向流模式下,如何在每条消息中携带轻量级权限 Token,实现消息级权限验证。
2.7 本章小结
- Protocol Buffers 提供强类型、向后兼容的接口定义,是权限元数据的基础载体。
- Service 定义 通过
.proto文件声明 RPC 方法,权限上下文应作为请求消息的内嵌字段。 - 四种通信模式 对权限验证的时机和粒度有不同要求:Unary 和 Server Streaming 适合流建立时单次校验;Client Streaming 和 Bidirectional Streaming 需要支持消息级增量验证。
- 流式场景 下,每条消息携带独立 Token 是实现动态权限控制的关键模式。