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 模式在客户端与服务端之间的消息流向,以及权限验证的介入点。

gRPC 四种通信模式与权限验证介入点 gRPC 四种通信模式与权限验证介入点 客户端 服务端 权限验证拦截器 ① Unary RPC 请求 响应 ② Server Streaming 请求 流响应 ③ Client Streaming 流请求 响应 ④ Bidirectional Streaming 流请求 流响应 验证介入点: Unary/Server Streaming 在流建立时 Client/Bidirectional 支持消息级

2.6 流式模式下的权限上下文传递

在流式 RPC 中,权限上下文不能仅依赖连接建立时的单次校验。下图展示了在双向流模式下,如何在每条消息中携带轻量级权限 Token,实现消息级权限验证。

双向流模式消息级权限验证流程 双向流模式消息级权限验证流程 客户端 服务端 Msg1 + Token_A 验证 Token_A Msg2 + Token_B 验证 Token_B Msg3 + Token_C 验证 Token_C 每条消息携带独立 Token,支持动态权限变更 服务端拦截器逐条验证,拒绝过期或越权消息

2.7 本章小结

  • Protocol Buffers 提供强类型、向后兼容的接口定义,是权限元数据的基础载体。
  • Service 定义 通过 .proto 文件声明 RPC 方法,权限上下文应作为请求消息的内嵌字段。
  • 四种通信模式 对权限验证的时机和粒度有不同要求:Unary 和 Server Streaming 适合流建立时单次校验;Client Streaming 和 Bidirectional Streaming 需要支持消息级增量验证。
  • 流式场景 下,每条消息携带独立 Token 是实现动态权限控制的关键模式。