gRPC入门指南 — 自定义认证(六)

点击上方蓝色“Golang来啦”关注我哟

加个“星标”,天天 15 分钟,掌握 Go 语言

前言

在前面的章节(文末推荐阅读)中,我们通过 TLS 证书的方式对通信数据进行了加密。另外,我们还可以给 RPC 方法添加自定义的验证方法,使得数据更加安全。这篇文章我们就以 Token 认证为例,介绍 gRPC 如何添加自定义验证方法。

自定义认证

gRPC 官方默认提供了用于自定义认证的接口,作用是将所需的安全认证信息添加到 RPC 方法的上下中。

type PerRPCCredentials interface {
 GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error)
 RequireTransportSecurity() bool
}
  • GetRequestMetadata() 获取当前请求认证所需的元数据;

  • RequireTransportSecurity() 是否需要基于 TLS 认证进行安全传输;

接下来我们自定义 token,实现这两个方法:

type Token struct {
 AppId     string
 AppSecret string
}

// GetRequestMetadata 获取当前请求认证所需的元数据
func (t *Token) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
 return map[string]string{"app_id": t.AppId, "app_secret": t.AppSecret}, nil
}

// RequireTransportSecurity 是否需要基于 TLS 认证进行安全传输
func (t *Token) RequireTransportSecurity() bool {
 return false
}

Server 端

完整的代码如下:

package main

import (
 "context"
 pb "go-grpc-example/6-rpc_auth/proto"
 "google.golang.org/grpc"
 "google.golang.org/grpc/codes"
 "google.golang.org/grpc/metadata"
 "google.golang.org/grpc/status"
 "log"
 "net"
)

const (
 Address string = ":8000"
 Network string = "tcp"
)

type SimpleService struct{}

func (s *SimpleService) GetSimpleInfo(ctx context.Context, req *pb.SimpleRequest) (*pb.SimpleResponse, error) {
 // 检测Token是否有效
 if err := check(ctx); err != nil {
  return nil, err
 }
 data := req.Data
 log.Printf("get from client: %v", data)

 resp := pb.SimpleResponse{
  Code:  1,
  Value: "gRPC",
 }
 return &resp, nil
}

func main() {

 listener, err := net.Listen(Network, Address)
 if err != nil {
  log.Fatalf("net.listen err: %v", err)
 }
 log.Println(Address, " net listening...")

 grpcServer := grpc.NewServer()

 pb.RegisterSimpleServer(grpcServer, &SimpleService{})

 err = grpcServer.Serve(listener)
 if err != nil {
  log.Fatalf("grpc server err: %v", err)
 }
}

func check(ctx context.Context) error {
 // 从上下文章获取元数据
 md, ok := metadata.FromIncomingContext(ctx)
 if !ok {
  return status.Errorf(codes.Unauthenticated, "获取token失败")
 }

 var (
  appId     string
  appSecret string
 )
 if value, ok := md["app_id"]; ok {
  appId = value[0]
 }
 if value, ok := md["app_secret"]; ok {
  appSecret = value[0]
 }
 if appId != "grpc_auth" || appSecret != "123456" {
  return status.Errorf(codes.Unauthenticated, "Token无效,appId:%v,appSecret:%v", appId, appSecret)
 }
 return nil
}

上面的代码,在 GetSimpleInfo() 方法中,在处理实际的业务逻辑之前,我们调用了 check() 函数验证 token 信息是否正确。

Client 端

完整的代码如下:

package main

import (
 "context"
 pb "go-grpc-example/5-security/proto"
 "google.golang.org/grpc"
 "log"
)

const Address = ":8000"

type Token struct {
 AppId     string
 AppSecret string
}

// GetRequestMetadata 获取当前请求认证所需的元数据
func (t *Token) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {
 return map[string]string{"app_id": t.AppId, "app_secret": t.AppSecret}, nil
}

// RequireTransportSecurity 是否需要基于 TLS 认证进行安全传输
func (t *Token) RequireTransportSecurity() bool {
 return false
}

func main() {

 // Token token认证
 token := Token{
  AppId:     "grpc_auth",
  AppSecret: "123456",
 }

 opts := []grpc.DialOption{
  grpc.WithInsecure(),
  grpc.WithPerRPCCredentials(&token),
 }

 conn, err := grpc.Dial(Address, opts...)
 if err != nil {
  log.Fatalf("dial conn err: %v", err)
 }
 defer conn.Close()

 grpcClient := pb.NewSimpleClient(conn)

 req := pb.SimpleRequest{
  Data: "seekload",
 }
 resp, err := grpcClient.GetSimpleInfo(context.Background(), &req)
 if err != nil {
  log.Fatalf("resp err: %v", err)
 }
 log.Printf("get from client,code: %v,value: %v", resp.Code, resp.Value)

}

上面的代码,自定义 token,实现了 gRPC 提供的两个方法。在客户端中调用 Dial() 时添加自定义验证方法。

grpc.WithPerRPCCredentials(&token)

验证

分别运行服务端和客户端,输出:

go run server.go
:8000  net listening...
get from client: seekload

go run client.go
get from client,code: 1,value: gRPC

可以制造 token 信息不正确,客户端返回错误:

resp err: rpc error: code = Unauthenticated desc = Token无效,appId:grpc_auth,appSecret:123457

思考

大家试想下,实际业务中肯定不止一个 RPC 方法,每个方法中都需要手动加一段验证 token 信息的代码,这样岂不是很繁琐。那有没有“一处验证,处处验证”的方法?答案肯定是有的,对!拦截器,这就是我们下一篇文章给大家介绍的。

推荐阅读:

gRPC入门指南 — 通过TLS建立安全连接(五)

gRPC入门指南 — 双向流式RPC(四)

资料下载

点击下方卡片关注公众号,发送特定关键字获取对应精品资料!

  • 回复「电子书」,获取入门、进阶 Go 语言必看书籍。

  • 回复「视频」,获取价值 5000 大洋的视频资料,内含实战项目(不外传)!

  • 回复「路线」,获取最新版 Go 知识图谱及学习、成长路线图。

  • 回复「面试题」,获取四哥精编的 Go 语言面试题,含解析。

  • 回复「后台」,获取后台开发必看 10 本书籍。

对了,看完文章,记得点击下方的卡片。关注我哦~ ????????????

如果您的朋友也在学习 gRPC,相信这篇文章对 TA 有帮助,欢迎转发分享给 TA,非常感谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Seekload

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值