gRPC持ち込み:RPCメソッドのカスタム認証


原文アドレス:gRPCを持ち込む:RPC方法に対してカスタム認証項目アドレスを行う:https://github.com/EDDYCJY/go...
前言
前の章では、グローバル認証に使用できる2つの方法について説明しました.
  • TLS証明書認証
  • CAに基づくTLS証明書認証
  • Unary and Stream interceptor

  • 実際のニーズでは、一部のモジュールのRPCメソッドに対して特別な認証や検証を行うことがよくあります.今日はこの機能点について説明し、実現します
    授業前の知識
    type PerRPCCredentials interface {
        GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error)
        RequireTransportSecurity() bool
    }

    各RPCメソッドのコンテキストに必要なセキュリティ認証情報を追加する役割を果たす、gRPCではPerRPCCredentialsがデフォルトで定義されています.これが本章の主役です.gRPCでは、カスタム認証用のインタフェースがデフォルトで提供されています.2つの方法があります.
  • GetRequestMetadata:現在の認証要求に必要なメタデータを取得する
  • RequireTransportSecurity:TLS認証に基づく安全な伝送が必要かどうか
  • .
    ディレクトリ構造
    新しいsimple_token_server/server.goとsimple_token_client/client.go、ディレクトリ構造は以下の通りです.
    go-grpc-example
    ├── client
    │   ├── simple_client
    │   ├── simple_http_client
    │   ├── simple_token_client
    │   └── stream_client
    ├── conf
    ├── pkg
    ├── proto
    ├── server
    │   ├── simple_http_server
    │   ├── simple_server
    │   ├── simple_token_server
    │   └── stream_server
    └── vendor

    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"
    
    type Auth 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()
        if err != 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))
        ...
    }

    Client側では、type PerRPCCredentials interfaceに必要な方法を重点的に実現し、2点に注目すればよい.
  • 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) {
        if err := 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, "      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]
        }
    
        if appKey != a.GetAppKey() || appSecret != a.GetAppSecret() {
            return status.Errorf(codes.Unauthenticated, "      Token   ")
        }
    
        return nil
    }
    
    func (a *Auth) GetAppKey() string {
        return "eddycjy"
    }
    
    func (a *Auth) GetAppSecret() string {
        return "20181005"
    }

    サーバ側では簡単ですが、実際にはmetadata.FromIncomingContextを呼び出してコンテキストからmetadataを取得し、異なるRPCメソッドで認証チェックを行います.
    検証#ケンショウ#
    serverを再起動します.goとclient.goは、以下の結果を得た.
    $ go run client.go
    2018/10/05 20:59:58 resp: gRPC Token Server

    クライアントを変更goの値は、製造両者が一致せず、無効な結果が得られます.
    $ go run client.go
    2018/10/05 21:00:05 client.Search err: rpc error: code = Unauthenticated desc = invalid token
    exit status 1

    いちいちめんどくさい
    私はあなたがきっと一つ一つ聞くと信じています.面倒でしょう.この考えを持っているあなたは、type PerRPCCredentials interfaceを遮断器(interceptor)にしなければなりません.
    まとめ
    この章では、RPCメソッドのカスタム認証について簡単に説明しますが、グローバルにしたい場合は、ブロックから手を出すことをお勧めします.
    リファレンス
    このシリーズのサンプルコード
  • go-grpc-example

  • シリーズディレクトリ
  • gRPC持ち込み:gRPC及び関連紹介
  • は、gRPC:gRPC Client and Server
  • に持ち込む.
  • は、gRPC:gRPC Streaming、Client and Server
  • を導入します.
  • はgRPC:TLS証明書認証
  • を持ち込む.
  • gRPC持ち込み:CAベースTLS証明書認証
  • gRPC:Unary and Stream interceptor
  • に持ち込む
  • はgRPCを持ち込みます:あなたのサービスにHTTPインタフェース
  • を同時に提供させます.
  • gRPC持ち込み:RPCメソッドのカスタム認証
  • gRPC:gRPC Deadlines
  • に持ち込む