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
}
校验通过
校验不通过
评论区