目 录CONTENT

文章目录
Go

GRPC.WithPerRPCCredentials 实现 Token 认证(客户端发送metadata的另一种姿势)

Hello!你好!我是村望~!
2023-05-31 / 0 评论 / 0 点赞 / 112 阅读 / 737 字
温馨提示:
我不想探寻任何东西的意义,我只享受当下思考的快乐~

GRPC.WithPerRPCCredentials 实现 Token 认证

参考链接:

实现对每个 gRPC 方法进行认证,需要实现 grpc.PerRPCCredentials 接口:

type PerRPCCredentials interface {
    // GetRequestMetadata gets the current request metadata, refreshing
    // tokens if required. This should be called by the transport layer on
    // each request, and the data should be populated in headers or other
    // context. If a status code is returned, it will be used as the status
    // for the RPC. uri is the URI of the entry point for the request.
    // When supported by the underlying implementation, ctx can be used for
    // timeout and cancellation.
    // TODO(zhaoq): Define the set of the qualified keys instead of leaving
    // it as an arbitrary string.
    GetRequestMetadata(ctx context.Context, uri ...string) (
        map[string]string,	error,
    )
    // RequireTransportSecurity indicates whether the credentials requires
    // transport security.
    RequireTransportSecurity() bool†
}
  • RequireTransportSecurity 用于指定是否要求在通信中使用传输层安全性(Transport Layer Security,TLS)。

    在 gRPC 中,RequireTransportSecurity 选项是用于配置服务器和客户端之间的安全连接。当设置为 true 时,它表示服务器和客户端之间必须使用 TLS 加密通信。这意味着所有的 gRPC 通信都需要在传输过程中进行加密,确保数据的机密性和完整性。

  • 在 gRPC 中,元数据是与每个请求关联的附加信息,它可以包含认证凭据、请求的上下文信息、身份验证令牌等。GetRequestMetadata 方法允许你自定义生成请求的元数据,以便在发送请求时将其附加到 gRPC 请求中。 对标一下之前学习过的 metadata 的用法!

下面就来实现一个之前使用metadata实现的token验证demo吧!

首先是 CLIENT 客户端,我们不再使用之前Metadata的方式传递元数据!我们自定义一个结构体,实现 PerRPCCredentials 接口!

type Authentication struct {
	Token string
}

func (a *Authentication) GetRequestMetadata(context.Context, ...string) (
	map[string]string, error,
) {
	return map[string]string{"token": a.Token}, nil
}
func (a *Authentication) RequireTransportSecurity() bool {
	return false
}

然后使用 WithPerRPCCredentials 传入自定义的 Authentication 生成我们的Diaoption!

// 建立 grpc与服务端套接字通信
conn, err := grpc.Dial(":8111", grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithPerRPCCredentials(&Authentication{Token: "xxx"}))
if err != nil {
	fmt.Println(err)
	return
}

服务端同样还是在拦截中!使用 FromIncomingContext 获取!

// CustomInterceptor 自定义拦截器结构体
type CustomInterceptor struct {
}

// UnaryServerInterceptor 实现拦截器的 UnaryServerInterceptor 方法里面就是具体的拦截器内部要做的拦截逻辑!
func (i *CustomInterceptor) UnaryServerInterceptor(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
	// 在处理请求之前执行的逻辑
	log.Println("CustomInterceptor: Before handling the request")
	if outgoingContext, b := metadata.FromIncomingContext(ctx); b {
		tokenSlice := outgoingContext.Get("token")
		if len(tokenSlice) < 1 || tokenSlice[0] != "xxx" {
			return nil, status.Error(codes.Unauthenticated, "无认证信息")
		}
	} else {
		return nil, status.Error(codes.Unauthenticated, "无认证信息")
	}

	// 调用下一个拦截器或服务处理程序
	resp, err := handler(ctx, req)

	// 在处理请求后执行的逻辑
	log.Println("CustomInterceptor: After handling the request")

	return resp, err
}

校验通过image-20230531143801260

校验不通过

image-20230531144533583

0

评论区