This is a creation in Article, where the information may have evolved or changed.
Interceptor
The GRPC server provides a interceptor function that takes precedence over the data in the request when the server receives the request and then transfers it to the specified service processing and response, similar to the middleware, which is a good place to process validation, logging, and so on.
In the example of custom token authentication, the authentication information is processed and certified by the methods in each service, and if there is a large number of interface methods, this posture is too painful, and each interface implementation must first process the authentication information. This time interceptor stand out to solve this problem, can be transferred to the specific interface before the request processing authentication information, a certification, everywhere worry-free, look at the code bar, modify the service-side implementation of the Hello-token project:
Server/main.go
Package Mainimport ("net" PB "Github.com/jergoo/go-grpc-example/proto" "Golang.org/x/net/context" "Google.gol Ang.org/grpc "Google.golang.org/grpc/codes"//GRPC Response status Code "Google.golang.org/grpc/credentials"//GRPC Certification Pack "Google.golang.org/grpc/grpclog" "google.golang.org/grpc/metadata"//GRPC Metadata Package) const (//Address GRPC service addresses Address = "127.0.0.1:50052")//define HelloService and implement the agreed interface type HelloService struct{}//helloservice ... var helloservice = Helloservice{}func (H helloservice) SayHello (CTX context. Context, in *PB. Hellorequest) (*PB. Helloreply, error) {resp: = new (Pb). helloreply) resp. Message = "Hello" + in. Name + "." Return resp, nil}//auth validation tokenfunc auth (ctx context. Context) Error {MD, OK: = metadata. Fromcontext (CTX) if!ok {return GRPC. Errorf (codes. Unauthenticated, "No token authentication information")} var (AppID string Appkey string) if val, ok: = md["AppID"]; OK {AppID = val[0]} If val, ok: = md["Appkey"]; OK {appkey = val[0]} if AppID! = "101010" | | Appkey! = "I am key" {return GRPC. Errorf (codes. Unauthenticated, "Token authentication information Invalid: appid=%s, appkey=%s", AppID, Appkey)} return Nil}func main () {listen, err: = Net . Listen ("TCP", Address) if err! = Nil {grpclog. Fatalf ("Failed to listen:%v", err)} var opts []grpc. Serveroption//TLS authentication creds, ERR: = credentials. Newservertlsfromfile (".. /.. /keys/server.pem ",". /.. /keys/server.key ") if err! = Nil {grpclog. Fatalf ("Failed to generate credentials%v", err)} opts = Append (opts, Grpc. Creds (creds))//Register Interceptor Var interceptor grpc. Unaryserverinterceptor Interceptor = func (CTX context. Context, req interface{}, Info *grpc. Unaryserverinfo, Handler Grpc. Unaryhandler) (Resp interface{}, err error) {err = Auth (ctx) if err! = Nil {return} Continue processing request return handler (CTX, req)} opts = Append (opts, Grpc. UnaryinterCeptor (Interceptor))//instantiation Grpc Server S: = Grpc. NewServer (opts ...) Register HelloService PB. Registerhelloserver (S, HelloService) Grpclog. Println ("Listen on" + Address + "with TLS + Token + Interceptor") S.serve (Listen)}
Run:
go run main.goListen on 50052 with TLS + Token
Client/main.go
Package Mainimport (pb "Github.com/jergoo/go-grpc-example/proto"//introduced Proto Pack "Golang.org/x/net/context" "Google. Golang.org/grpc "Google.golang.org/grpc/credentials"//Introducing GRPC Authentication Package "Google.golang.org/grpc/grpclog") const (//Ad Dress GRPC Service address = "127.0.0.1:50052"//Opentls whether to turn on TLS authentication OPENTLS = true)//customcredential Custom Authentication Type cust Omcredential Struct{}func (c customcredential) Getrequestmetadata (CTX context. Context, Uri, String) (map[string]string, error) {return map[string]string{"AppID": "101010", "Appke Y ":" I am Key ",}, Nil}func (c customcredential) requiretransportsecurity () bool {if OPENTLS {return true } return False}func Main () {var err error var opts []GRPC. Dialoption if OPENTLS {//TLS connection creds, err: = credentials. Newclienttlsfromfile (".. /.. /keys/server.pem "," server name ") If err! = Nil {grpclog. Fatalf ("Failed to create TLS credentials%v", err)} opts = append (opts, Grpc. Withtransportcredentials (creds))} else {opts = append (opts, Grpc. Withinsecure ())}//Specify custom Authentication opts = Append (opts, Grpc. Withperrpccredentials (New (customcredential))) conn, err: = Grpc. Dial (Address, opts ...) If err! = Nil {grpclog. Fatalln (ERR)} defer conn. Close ()//Initialize client c: = PB. Newhelloclient (conn)//Call method Reqbody: = new (Pb). hellorequest) Reqbody.name = "Grpc" r, Err: = C.sayhello (context. Background (), reqbody) if err! = Nil {grpclog. Fatalln (Err)} grpclog. Println (R.message)}
Run the client program Client/main.go:
go run main.go// 认证成功结果Hello gRPCToken info: appid=101010,appkey=i am key// 认证失败结果:rpc error: code = 16 desc = Token认证信息无效: appID=101010, appKey=i am not key
Run the results and Hello-token project, simple No, just need to register the server before the interceptor, you can easily solve the problem of the egg pain, want to register a few to register a few.
Project recommendation:
Go-grpc-middleware
This project encapsulates the interceptor and supports chained assembly of multiple interceptors, which is easier to use in places where multiple processing is required.
Reference
Sample code for this series