I use gRPC-Gateway for RESTful API and gRPC server. Here is my code:
func main() {
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
defer cancel()
// rest server
go func() {
mux := runtime.NewServeMux()
opts := []grpc.DialOption{grpc.WithInsecure()}
err := pb.RegisterXYZHandlerFromEndpoint(ctx, mux, *grpcServerEndpoint, opts)
if err != nil {
// Err
}
if err := http.ListenAndServe(":8080", mux); err != nil {
// Err
}
}()
// grpc server
l, err := net.Listen("tcp", ":9090")
if err != nil {
// Err
}
xyzSvc := server.Init()
s := grpc.NewServer(
grpc.UnaryInterceptor(
server.AuthenticateInterceptor(xyzSvc),
),
)
pb.RegisterXYZServiceServer(s, xyzSvc)
fmt.Println("GRPC on port 9090, REST Server on port 8080")
if err := s.Serve(l); err != nil {
// Err
}
}
Here line server.AuthenticateInterceptor(xyzSvc) added authentication which works fine.
But the problem is I want to add RBAC(Role Base Access Control) with different endpoint. Something like:
mux.HandlePath("GET", "/v1/users", AuthMiddleware(RBACMiddleware("user")))
mux.HandlePath("POST", "/v1/users", AuthMiddleware(RBACMiddleware("admin")))
I know I can't do it because my endpoints are already generated by gRPC-Gateway according to *.proto file.
Is there any idea to add RBAC with gRPC-Gateway?
To implement RBAC (Role-Based Access Control) with a gRPC-Gateway generated RESTful API, you would need to integrate your RBAC logic within the gRPC server's interceptors, as the gRPC-Gateway acts as a reverse proxy translating RESTful HTTP APIs into gRPC calls.
By handling RBAC at the gRPC level, you make sure access control is enforced regardless of whether the client is using REST or gRPC directly.
That would involve to:
An RBAC interceptor in your gRPC server setup would look like (a bit like
NguyenTrungTin/go-grpc-boilerplatepkg/interceptor/auth.go):Assuming Go 1.20+ and the generic slices.Contains() availability:
As mentioned before, the grpc-gateway serves as a bridge between HTTP/REST and gRPC by generating HTTP handlers from your gRPC services defined in the
.protofiles. It does not directly support attaching middleware to individual routes because it dynamically translates HTTP requests to gRPC and vice versa, without exposing direct control over the HTTP routing layer in the same way a traditional HTTP server framework might.As an alternative approach (to achieve RBAC at the HTTP level with grpc-gateway), you might consider applying middleware at the global level to your HTTP server. That middleware can inspect incoming requests and apply RBAC checks based on the request path and method. That would allow you to enforce RBAC but requires custom logic to map HTTP routes to roles.
Or, as another option, you would create a custom HTTP handler that wraps the grpc-gateway mux (a bit like what is mentioned for tracing). That handler would intercept all HTTP requests, perform RBAC checks for specific routes, and then delegate to the grpc-gateway mux for routes that pass the RBAC check.
Both approaches require you to implement the logic for
determineRoleanduserHasRole, which would typically involve extracting the user's role from the request context, likely populated by an earlier authentication middleware.It is still not a direct route-specific middleware application that you want, because of the design of grpc-gateway, which focuses on simplicity and uniformity in exposing gRPC services as RESTful APIs, rather than offering granular control over HTTP request handling.