RBAC(基于角色的访问控制)与 gRPC 网关生成的 RESTful API

问题描述 投票:0回答:1

我使用 gRPC-Gateway 作为 RESTful API 和 gRPC 服务器。这是我的代码:

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
    }
}

这里第

server.AuthenticateInterceptor(xyzSvc)
行添加了身份验证,效果很好。

但问题是我想添加具有不同端点的 RBAC(角色基础访问控制)。比如:

mux.HandlePath("GET", "/v1/users", AuthMiddleware(RBACMiddleware("user")))
mux.HandlePath("POST", "/v1/users", AuthMiddleware(RBACMiddleware("admin")))

我知道我不能这样做,因为我的端点已经由 gRPC-Gateway 根据

*.proto
文件生成了。

有什么想法可以通过 gRPC-Gateway 添加 RBAC 吗?

go rbac grpc-go grpc-getway
1个回答
0
投票

要使用 gRPC-Gateway 生成的 RESTful API 实现 RBAC(基于角色的访问控制),您需要将 RBAC 逻辑集成到 gRPC 服务器的拦截器中,因为 gRPC-Gateway 充当转换 RESTful 的反向代理HTTP API 转入 gRPC 调用。
通过在 gRPC 级别处理 RBAC,您可以确保无论客户端是直接使用 REST 还是 gRPC,都强制实施访问控制。

这将涉及:

  • 明确定义系统中的角色以及每个角色拥有哪些权限。
  • 创建用于身份验证和授权 (RBAC) 的中间件功能。身份验证中间件应该对用户进行身份验证并将用户的角色附加到上下文。 RBAC 中间件应根据端点所需的角色检查用户的角色。
  • 使用 gRPC 拦截器应用您的 RBAC 逻辑,因为您的 REST 端点是自动生成的,并且您无法像在典型的 HTTP 服务器中那样直接附加中间件。

gRPC 服务器设置中的 RBAC 拦截器看起来像(有点像

NguyenTrungTin/go-grpc-boilerplate
pkg/interceptor/auth.go
):

假设 Go 1.20+ 和 generic slices.Contains() 可用性:

package server

import (
    "context"
    "google.golang.org/grpc"
    "google.golang.org/grpc/codes"
    "google.golang.org/grpc/metadata"
    "google.golang.org/grpc/status"
    "slices"
)

// AuthenticateInterceptor authenticates requests
func AuthenticateInterceptor(svc *XYZService) grpc.UnaryServerInterceptor {
    return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) {
        // Authentication logic here
        // Assume we extract user info and roles from the request and add it to the context
        ctx = context.WithValue(ctx, "roles", []string{"user", "admin"}) // Example: Add roles to context
        return handler(ctx, req)
    }
}

// RBACInterceptor checks if the user has the required role to access the endpoint
func RBACInterceptor(requiredRole string) grpc.UnaryServerInterceptor {
    return func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
        roles, ok := ctx.Value("roles").([]string)
        if !ok || !slices.Contains(roles, requiredRole) {
            return nil, status.Errorf(codes.PermissionDenied, "access denied")
        }
        return handler(ctx, req)
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.