gRPC授权方法

4
我在开发 Go gRPC 服务并实现授权功能。字面意思是基于 JWT 的声明允许或禁止访问 gRPC 方法。
我在 grpc.UnaryServerInterceptor 层级上进行 JWT 解析,提取声明并将其填充到上下文中的值,如果没有 JWT 或者 JWT 不正确则未经身份验证。
func (s *Server) GetSomething(ctx context.Context, req *GetSomething Request) (*GetSomething Response, error) {
    if hasAccessTo(ctx, req.ID) {
        //some work here
    }
}

func hasAccessTo(ctx context.Context, string id) {
    value := ctx.Value(ctxKey).(MyStruct)
    //some work here

}

那么,我想知道是否有一些通用的授权/身份验证实践可以避免在每个grpc服务器方法中写样板代码?


1
也许 go-kit 的架构可以帮助您构建服务的结构。 - RickyA
1
我曾经看到过类似的东西,其中样板代码被放在一个库中,为处理程序函数提供了一个包装器函数。然后有一种策略系统,每个端点定义所需的权限,这些权限映射到角色(基于JWT中的身份声明)。 - Havelock
如果您想保护每个调用,那么是的,请使用UnaryInterceptor。如果您需要一个可行的示例,我可以提供一个。 - Trevor V
@Varcorb 如果你能发布那就太好了。 - Sergii Getman
这里有一个OAuth示例,可能会有所帮助:https://github.com/grpc/grpc-go/tree/master/examples/features/authentication - menghanl
1个回答

4

如果您想在每个请求上验证jwt,可以像这样调用UnaryInterceptor

// middleware for each rpc request. This function verifies the client has the correct "jwt".
func authInterceptor(ctx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
    meta, ok := metadata.FromIncomingContext(ctx)
    if !ok {
        return nil, status.Error(codes.Unauthenticated, "INTERNAL_SERVER_ERROR")
    }
    if len(meta["jwt"]) != 1 {
        return nil, status.Error(codes.Unauthenticated, "INTERNAL_SERVER_ERROR")
    }

    // if code here to verify jwt is correct. if not return nil and error by accessing meta["jwt"][0]

    return handler(ctx, req) // go to function.
}

在客户端的context中使用metadata来传递jwt字符串进行验证。
在您的主函数中,记得像这样注册它。
// register server
myService := grpc.NewServer(
    grpc.UnaryInterceptor(authInterceptor), // use auth interceptor middleware
)
pb.RegisterTheServiceServer(myService, &s)
reflection.Register(myService)

您的客户需要像这样调用您的服务器:

您的客户需要像这样调用您的服务器:

// create context with token and timeout
ctx, cancel := context.WithTimeout(metadata.NewOutgoingContext(context.Background(), metadata.New(map[string]string{"jwt": "myjwtstring"})), time.Second*1)
defer cancel()

1
谢谢,我在我的拦截器中也做了类似的事情。但是我正在寻找一种更高级的方法,而不仅仅是检查是否有jwt。 我正在寻找某种授权方式: 该用户是否被允许访问该方法 - Sergii Getman
@SergiiGetman - 他的回答忽略了传递到函数中的 *grpc.UnaryServerInfo,但它包含了我认为对你有用的信息。例如,它有一个 .FullMethod 属性,允许你针对每个方法执行不同的授权逻辑。 - domoarigato

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接