目录
前言
个人网站:https://linzyblog.netlify.app/
示例代码已经上传到github:点击跳转
gRPC官方文档:点击跳转
在前面的章节中,我们介绍了两种可全局认证的方法:而在实际需求中,常常会对某些模块的 RPC 方法做特殊认证或校验,而gRPC也专门提供了这类特殊认证的接口。
一、概述
gRPC为每个gRPC方法调用提供了Token认证支持,可以基于用户传入的Token判断用户是否登陆、以及权限等,实现Token认证的前提是,需要定义一个结构体,并实现credentials.PerRPCCredentials
接口。
1、credentials.PerRPCCredentials 接口
类型定义:
type PerRPCCredentials interface {
// 返回需要认证的必要信息
GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error)
// 是否使用安全链接(TLS)
RequireTransportSecurity() bool
}
在 gRPC 中默认定义了 PerRPCCredentials
,是 gRPC 默认提供用于自定义认证的接口,它的作用是将所需的安全认证信息添加到每个 RPC 方法的上下文中。其包含 2 个方法:
GetRequestMetadata
:获取当前请求认证所需的元数据(metadata),以 map 的形式返回本次调用的授权信息,ctx 是用来控制超时的RequireTransportSecurity
:是否需要基于 TLS 认证进行安全传输,如果返回 true 则说明该 Credentials 需要在一个有 TLS 认证的安全连接上传输,如果当前连接并没有使用 TLS 则会报错:
transport: cannot send secure credentials on an insecure connection
2、实现流程
- 在发出请求之前,gRPC 会将 Credentials(认证凭证)存放在 metadata(元数据)中进行传递。
- 在真正发起调用之前,gRPC 会通过 GetRequestMetadata函数,将用户定义的 Credentials(认证凭证)提取出来,并添加到 metadata(元数据)中,随着请求一起传递到服务端。
- 然后服务端从 metadata 中取出 Credentials 进行有效性校验。
二、实现自定义身份验证
具体分为以下两步:
- 1)客户端请求时带上 Credentials;
- 2)服务端取出 Credentials,并验证有效性,一般配合拦截器使用(这里我们使用两种方法,拦截器以及RPC方法)。
1、目录结构
go-grpc-example
├─client
│ ├─token_client
│ │ └──client.go
├─pkg
│ ├─token
│ │ └──token.go
├─proto
│ ├─token
│ │ └──token.proto
└─server
├─token_server
│ └──server.go
2、编写IDL
在 proto/token 文件夹下的 token.proto 文件中,写入如下内容:
syntax = "proto3";
option go_package = "./proto/token;token";
package tokenservice;
// 验证参数
message TokenValidateParam {
string token = 1;
int32 uid = 2;
}
// 请求参数
message Request {
string name = 1;
}
// 请求返回
message Response {
int32 uid = 1;
string name = 2;
}
// 服务
service TokenService {
rpc Token(Request) returns (Response);
}
在Makefile文件中写入:
token:
protoc --go_out=. --go-grpc_out=. ./proto/token/*.proto
用make token
指令生成Go代码:
➜ make token
protoc --go_out=. --go-grpc_out=. ./proto/token/*.proto
3、编写基础模板和空定义
我们先把基础的模板和空定义写出来在进行完善
1)server.go
const Address = "127.0.0.1:8888"
type TokenService struct {
token.UnimplementedTokenServiceServer
}
func main(