设为首页 加入收藏

TOP

grpc中的拦截器(五)
2023-07-23 13:29:45 】 浏览:94
Tags:grpc
Info, handler grpc.UnaryHandler) (resp interface{}, err error)

参数 info 包含了这个 RPC 的所有信息,拦截器可以对其进行操作。 而handler是服务方法实现的包装器。 拦截器负责调用处理程序来完成 RPC。

1、定义一个服务端的鉴权一元拦截器
func ServerUnaryInterceptorCustom() grpc.ServerOption {
	serverInterceptor := func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
		start := time.Now()

    // 如果是非登录请求,需要验证token
		if info.FullMethod != "/helloservice.HelloService/Login" {
			if err := authorize(ctx); err != nil {
				return nil, err
			}
		}

		h, err := handler(ctx, req)

		log.Printf("Request - Method:%s\tDuration:%s\tError:%v\n",
			info.FullMethod,
			time.Since(start),
			err)
		return h, err
	}
	return grpc.UnaryInterceptor(serverInterceptor)
}

// authorize 从Metadata中获取token并校验是否合法
func authorize(ctx context.Context) error {
  // 从context中获取metadata
	md, ok := metadata.FromIncomingContext(ctx)
	if !ok {
		return status.Errorf(codes.InvalidArgument, "Retrieving metadata is failed")
	}

	authHeader, ok := md["authorization"]
	if !ok {
		return status.Errorf(codes.Unauthenticated, "Authorization token is not supplied")
	}

	token := authHeader[0]
	// validateToken function validates the token
	err := validateToken(token)

	if err != nil {
		return status.Errorf(codes.Unauthenticated, err.Error())
	}
	return nil
}

func validateToken(token string) error {
	// 校验token
	return nil
}

我们可以看下我们定义的一元拦截器的执行流程:

  1. 首先进来之后我们判断如果是登录请求,直接转发请求,并打印日志
  2. 如果是非登录请求,需要验证token,调用authorize方法
  3. 在authorize方法中,会从context中获取metadata元数据,然后解析获取token并验证

请注意,前面代码块中的拦截器逻辑使用包 google.golang.org/grpc/codes 和 google.golang.org/grpc/status。

2、grpc客户端传入token

gRPC 支持在客户端和服务器之间使用 Context 值发送元数据。 google.golang.org/grpc/metadata 包提供了元数据的功能。

其中MD类型是一个k-v的map,想下面这样

type MD map[string][]string

下面我们在客户端编写向服务端发送token的代码,我们修改下客户端的unaryRpc,构造包含authorization的metadata:

func unaryRpc(conn *grpc.ClientConn) {
	client := helloservice.NewHelloServiceClient(conn)
	ctx := context.Background()
  // 构造元数据,并返回MD类型的结构
	md := metadata.Pairs("authorization", "mytoken")
  // 元数据塞入context并返回新的context
	ctx = metadata.NewOutgoingContext(ctx, md)
	reply, err := client.Hello(ctx, &helloservice.String{Value: "hello"})
	if err != nil {
		log.Fatal(err)
	}
	log.Println("unaryRpc recv: ", reply.Value)
}

这样元数据的信息就会跟着context发送到grpc服务端。

接着我们在服务端grpc中修改如下代码,加入一行日志:

func validateToken(token string) error {
	log.Printf("get the token: %s \n", token)
	// 校验token
	return nil
}
3、运行服务

我们重新执行下grpc服务端程序,然后运行下客户端代码,可以看到token传过来了:

go run helloservice/main/main.go
2022/10/15 20:36:04 server started...
2022/10/15 20:36:08 get the token: mytoken 
2022/10/15 20:36:09 Request - Method:/helloservice.HelloService/Hello   Duration:1.001216763s   Error:<nil>

2、StreamServerInterceptor

为了创建 StreamServerInterceptor,通过提供 StreamServerInterceptor func 值作为参数调用 StreamInterceptor 函数,该参数返回为服务器设置 StreamServerInterceptor 的 grpc.ServerOption 值。

func StreamInterceptor(i StreamServerInterceptor) ServerOption {
	return newFuncServerOption(func(o *serverOptions) {
		if o.streamInt != nil {
			panic("The stream server interceptor was already set a
首页 上一页 2 3 4 5 下一页 尾页 5/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇golang中的变量阴影 下一篇golang开发一个简单的grpc

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目