GRPC CAPTCHA验证器中间件
#go #grpc #protocolbuffers

GRPC CAPTCHA验证中间件是一个GO模块,它提供了可重复使用的中间件组件,用于验证GRPC服务器上的验证码挑战。中间件拦截传入请求,使用可配置的提供商验证请求的验证码挑战,并在挑战无效时拒绝请求。

该模块设计为可配置,并具有指定验证码提供商,挑战验证端点的选项以及验证请求的自定义标头。它使用Google Protobuf库来解析GRPC方法描述符,并提取使用Protobuf扩展定义的自定义选项。

特征

  • 支持Google,Cloudflare,HCAPTCHA提供商验证挑战
  • 支持Unary和流服务器中间件
  • 特定RPC方法的CAPTCHA验证

安装(GO> = 1.18)

$ go get -u github.com/GoFarsi/grpc-captcha-validation

文档:https://pkg.go.dev/github.com/GoFarsi/grpc-captcha-validation

例子

GRPC服务器的示例CAPTCHA:

syntax = "proto3";
package example;
option go_package = "github.com/GoFarsi/grpc-captcha-validation/_example/proto";

import "captcha.proto";

service GreetingService {
  rpc Greeting(GreetingRequest) returns(GreetingResponse) {
    option(captcha.captcha) = {
      check_challenge: true,
      provider: GOOGLE,
    };
  }

  rpc GreetingStream(stream GreetingRequest) returns(stream GreetingResponse) {
    option(captcha.captcha) = {
      check_challenge: true,
      provider: GOOGLE,
    };
  }
}

message GreetingRequest {
  string name = 1;
}

message GreetingResponse {
  string message = 1;
}
package main

import (
    "context"
    "fmt"
    gcv "github.com/GoFarsi/grpc-captcha-validation"
    "github.com/GoFarsi/grpc-captcha-validation/_example/proto"
    "google.golang.org/grpc"
    "google.golang.org/grpc/reflection"
    "io"
    "log"
    "net"
)

type GreetingService struct {
    proto.UnimplementedGreetingServiceServer
}

func (g *GreetingService) Greeting(ctx context.Context, in *proto.GreetingRequest) (*proto.GreetingResponse, error) {
    return &proto.GreetingResponse{
        Message: fmt.Sprintf("greeting %s", in.Name),
    }, nil
}

func (g *GreetingService) GreetingStream(srv proto.GreetingService_GreetingStreamServer) error {
    ctx := srv.Context()
    for {
        select {
        case <-ctx.Done():
            return ctx.Err()
        default:
        }

        req, err := srv.Recv()
        if err == io.EOF {
            log.Println("exit")
            return nil
        }
        if err != nil {
            log.Printf("receive error %v", err)
            continue
        }

        resp := proto.GreetingResponse{Message: fmt.Sprintf("Greeting %s", req.Name)}
        if err := srv.Send(&resp); err != nil {
            log.Printf("send error %v", err)
        }
    }
}

func main() {
    listener, err := net.Listen("tcp", ":8080")
    if err != nil {
        log.Fatalln(err)
    }

    c := gcv.NewCaptcha("foo", "", "", "")

    srv := grpc.NewServer(
        grpc.ChainUnaryInterceptor(c.UnaryServerInterceptor()),
        grpc.ChainStreamInterceptor(c.StreamServerInterceptor()),
    )

    reflection.Register(srv)

    proto.RegisterGreetingServiceServer(srv, &GreetingService{})

    log.Fatalln(srv.Serve(listener))
}