preface

Hello, I am fish fry. In the previous chapter, we introduced two methods of global authentication:

  1. TLS Certificate Authentication
  2. Ca-based TLS certificate authentication
  3. Unary and Stream interceptor

In practice, RPC methods of some modules are often authenticated or verified. Today we will explain and implement this function point

Knowledge before class

typePerRPCCredentials interface { GetRequestMetadata(ctx context.Context, uri ... string) (map[string]string, error) RequireTransportSecurity() bool }Copy the code

The PerRPCCredentials are defined by default in gRPC, which is the focus of this section. By default, gRPC provides an interface for custom authentication, which adds the required security authentication information to the context of each RPC method. It contains two methods:

  • GetRequestMetadata: Obtain the metadata required for authentication of the current request.
  • RequireTransportSecurity: specifies whether TLS authentication is required for secure transmission

The directory structure

Go and simple_token_client/client.go. The directory structure is as follows:

├─ │ ├─ Simple_http_├ ─ Simple_token_client │ ├─ Simple_token_client │ ├─ Simple_token_client │ ├─ ├ ─ ─ the conf ├ ─ ─ PKG ├ ─ ─ proto ├ ─ ─ server │ ├ ─ ─ simple_http_server │ ├ ─ ─ simple_server │ ├ ─ ─ simple_token_server │ └ ─ ─ Stream_server └ ─ ─ vendorCopy the code

gRPC

Client

package main

import (
	"context"
	"log"

	"google.golang.org/grpc"

	"github.com/EDDYCJY/go-grpc-example/pkg/gtls"
	pb "github.com/EDDYCJY/go-grpc-example/proto"
)

const PORT = "9004"

typeAuth struct { AppKey string AppSecret string } func (a *Auth) GetRequestMetadata(ctx context.Context, uri ... string) (map[string]string, error) {return map[string]string{"app_key": a.AppKey, "app_secret": a.AppSecret}, nil
}

func (a *Auth) RequireTransportSecurity() bool {
	return true
}

func main() {
	tlsClient := gtls.Client{
		ServerName: "go-grpc-example",
		CertFile:   ".. /.. /conf/server/server.pem",
	}
	c, err := tlsClient.GetTLSCredentials()
	iferr ! = nil { log.Fatalf("tlsClient.GetTLSCredentials err: %v", err)
	}

	auth := Auth{
		AppKey:    "eddycjy",
		AppSecret: "20181005",
	}
	conn, err := grpc.Dial(":"+PORT, grpc.WithTransportCredentials(c), grpc.WithPerRPCCredentials(&auth))
	...
}
Copy the code

On the Client side, implement the methods required by the Type PerRPCCredentials Interface. Note the following:

  • Struct Auth: GetRequestMetadata, RequireTransportSecurity
  • grpc.WithPerRPCCredentials

Server

package main

import (
	"context"
	"log"
	"net"

	"google.golang.org/grpc"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/metadata"
	"google.golang.org/grpc/status"

	"github.com/EDDYCJY/go-grpc-example/pkg/gtls"
	pb "github.com/EDDYCJY/go-grpc-example/proto"
)

type SearchService struct {
	auth *Auth
}

func (s *SearchService) Search(ctx context.Context, r *pb.SearchRequest) (*pb.SearchResponse, error) {
	iferr := s.auth.Check(ctx); err ! = nil {return nil, err
	}
	return &pb.SearchResponse{Response: r.GetRequest() + " Token Server"}, nil
}

const PORT = "9004"

func main() {... }type Auth struct {
	appKey    string
	appSecret string
}

func (a *Auth) Check(ctx context.Context) error {
	md, ok := metadata.FromIncomingContext(ctx)
	if! ok {return status.Errorf(codes.Unauthenticated, "Failed to customize authentication Token")
	}

	var (
		appKey    string
		appSecret string
	)
	if value, ok := md["app_key"]; ok {
		appKey = value[0]
	}
	if value, ok := md["app_secret"]; ok {
		appSecret = value[0]
	}

	ifappKey ! = a.GetAppKey() || appSecret ! = a.GetAppSecret() {
		return status.Errorf(codes.Unauthenticated, "Invalid custom authentication Token")}return nil
}

func (a *Auth) GetAppKey() string {
	return "eddycjy"
}

func (a *Auth) GetAppSecret() string {
	return "20181005"
}
Copy the code

On the Server side is more simple, the actual is called metadata. FromIncomingContext get the metadata from the context, then authentication checks in the different methods of RPC

validation

Restart server.go and client.go with the following results:

$ go run client.go
2018/10/05 20:59:58 resp: gRPC Token Server
Copy the code

Error: Client. go (); error: client.go ();

$ go run client.go
2018/10/05 21:00:05 client.Search err: rpc error: code = Unauthenticated desc = invalid token
exit status 1
Copy the code

Adding them one by one is too much trouble

I’m sure you’ll ask each one. Isn’t it too much trouble? You should make the Type PerRPCCredentials Interface an interceptor.

conclusion

This section is relatively simple, mainly for RPC method custom authentication is introduced, if you want to do global, the suggestion is to start from interceptor oh.

?

If you have any questions or mistakes, welcome to raise questions or give correction opinions on issues. If you like or are helpful to you, welcome Star, which is a kind of encouragement and promotion for the author.

My official account

reference

Sample code for this series

  • go-grpc-example