Golang gRPC實踐 連載四 gRPC認證

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

gRPC 預設提供了兩種認證方式:

  • 基於SSL/TLS認證方式

  • 遠程調用認證方式

兩種方式可以混合使用

TLS認證樣本

這裡直接擴充hello項目,實現TLS認證機制

首先需要準備認證,在hello目錄建立keys目錄用於存放認證檔案。

認證製作

製作私密金鑰 (.key)

# Key considerations for algorithm "RSA" ≥ 2048-bitopenssl genrsa -out server.key 2048    # Key considerations for algorithm "ECDSA" ≥ secp384r1# List ECDSA the supported curves (openssl ecparam -list_curves)openssl ecparam -genkey -name secp384r1 -out server.key

自簽名公開金鑰(x509) (PEM-encodings .pem|.crt)

openssl req -new -x509 -sha256 -key server.key -out server.pem -days 3650

自訂資訊

-----Country Name (2 letter code) [AU]:CNState or Province Name (full name) [Some-State]:XxXxLocality Name (eg, city) []:XxXxOrganization Name (eg, company) [Internet Widgits Pty Ltd]:XX Co. LtdOrganizational Unit Name (eg, section) []:DevCommon Name (e.g. server FQDN or YOUR name) []:server nameEmail Address []:xxx@xxx.com

目錄結構

$GOPATH/src/grpc-go-practice/example/|—— hello-tls/    |—— client/        |—— main.go   // 用戶端    |—— server/        |—— main.go   // 服務端|—— keys/                 // 認證目錄    |—— server.key    |—— server.pem|—— proto/    |—— hello.proto   // proto描述檔案    |—— hello.pb.go   // proto編譯後檔案

範例程式碼

proto/helloworld.protoproto/hello.pb.go檔案不需要改動

修改服務端代碼:server/main.go

package mainimport (    "net"    pb "go-grpc-practice/example/proto"    "golang.org/x/net/context"    "google.golang.org/grpc"    "google.golang.org/grpc/credentials" // 引入grpc認證包    "google.golang.org/grpc/grpclog")const (    // Address gRPC服務地址    Address = "127.0.0.1:50052")// 定義helloService並實現約定的介面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}func main() {    listen, err := net.Listen("tcp", Address)    if err != nil {        grpclog.Fatalf("failed to listen: %v", err)    }    // TLS認證    creds, err := credentials.NewServerTLSFromFile("../../keys/server.pem", "../../keys/server.key")    if err != nil {        grpclog.Fatalf("Failed to generate credentials %v", err)    }    // 執行個體化grpc Server, 並開啟TLS認證    s := grpc.NewServer(grpc.Creds(creds))    // 註冊HelloService    pb.RegisterHelloServer(s, HelloService)    grpclog.Println("Listen on " + Address + " with TLS")    s.Serve(listen)}

運行:

go run main.goListen on 127.0.0.1:50052 with TLS

服務端在執行個體化grpc Server時,可配置多種選項,TLS認證是其中之一

用戶端添加TLS認證:client/main.go

package mainimport (    pb "go-grpc-practice/example/proto" // 引入proto包    "golang.org/x/net/context"    "google.golang.org/grpc"    "google.golang.org/grpc/credentials" // 引入grpc認證包    "google.golang.org/grpc/grpclog")const (    // Address gRPC服務地址    Address = "127.0.0.1:50052")func main() {    // TLS串連    creds, err := credentials.NewClientTLSFromFile("../../keys/server.pem", "server name")    if err != nil {        grpclog.Fatalf("Failed to create TLS credentials %v", err)    }    conn, err := grpc.Dial(Address, grpc.WithTransportCredentials(creds))    if err != nil {        grpclog.Fatalln(err)    }    defer conn.Close()    // 初始化用戶端    c := pb.NewHelloClient(conn)    // 調用方法    reqBody := new(pb.HelloRequest)    reqBody.Name = "gRPC"    r, err := c.SayHello(context.Background(), reqBody)    if err != nil {        grpclog.Fatalln(err)    }    grpclog.Println(r.Message)}

運行:

go run main.goHello gRPC

用戶端添加TLS認證的方式和服務端類似,在建立串連Dial時,同樣可以配置多種選項,後面的樣本中會看到更多的選項。

Token認證樣本

再進一步,繼續擴充hello-tls項目,實現TLS + Token認證機制

目錄結構

$GOPATH/src/grpc-go-practice/example/|—— hello-token/    |—— client/        |—— main.go   // 用戶端    |—— server/        |—— main.go   // 服務端|—— keys/             // 認證目錄    |—— server.key    |—— server.pem|—— proto/    |—— hello.proto   // proto描述檔案    |—— hello.pb.go   // proto編譯後檔案

範例程式碼

用戶端實現:client/main.go

package mainimport (    pb "go-grpc-practice/example/proto" // 引入proto包    "golang.org/x/net/context"    "google.golang.org/grpc"    "google.golang.org/grpc/credentials" // 引入grpc認證包    "google.golang.org/grpc/grpclog")const (    // Address gRPC服務地址    Address = "127.0.0.1:50052"    // OpenTLS 是否開啟TLS認證    OpenTLS = true)// customCredential 自訂認證type customCredential struct{}func (c customCredential) GetRequestMetadata(ctx context.Context, uri ...string) (map[string]string, error) {    return map[string]string{        "appid":  "101010",        "appkey": "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串連        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())    }    // 使用自訂認證    opts = append(opts, grpc.WithPerRPCCredentials(new(customCredential)))    conn, err := grpc.Dial(Address, opts...)    if err != nil {        grpclog.Fatalln(err)    }    defer conn.Close()    // 初始化用戶端    c := pb.NewHelloClient(conn)    // 調用方法    reqBody := new(pb.HelloRequest)    reqBody.Name = "gRPC"    r, err := c.SayHello(context.Background(), reqBody)    if err != nil {        grpclog.Fatalln(err)    }    grpclog.Println(r.Message)}

這裡我們定義了一個customCredential結構,並實現了兩個方法GetRequestMetadataRequireTransportSecurity。這是gRPC提供的自訂認證方式,每次RPC調用都會傳輸認證資訊。customCredential其實是實現了grpc/credential包內的PerRPCCredentials介面。每次調用,token資訊會通過請求的metadata傳輸到服務端。下面具體看一下服務端如何擷取metadata中的資訊。

修改server/main.go中的SayHello方法:

package mainimport (    "fmt"    "net"    pb "go-grpc-practice/example/proto"    "golang.org/x/net/context"    "google.golang.org/grpc"    "google.golang.org/grpc/codes"    "google.golang.org/grpc/credentials" // 引入grpc認證包    "google.golang.org/grpc/grpclog"    "google.golang.org/grpc/metadata" // 引入grpc meta包)const (    // Address gRPC服務地址    Address = "127.0.0.1:50052")// 定義helloService並實現約定的介面type helloService struct{}// HelloService ...var HelloService = helloService{}func (h helloService) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {    // 解析metada中的資訊並驗證    md, ok := metadata.FromContext(ctx)    if !ok {        return nil, grpc.Errorf(codes.Unauthenticated, "無Token認證資訊")    }    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 nil, grpc.Errorf(codes.Unauthenticated, "Token認證資訊無效: appid=%s, appkey=%s", appid, appkey)    }    resp := new(pb.HelloReply)    resp.Message = fmt.Sprintf("Hello %s.\nToken info: appid=%s,appkey=%s", in.Name, appid, appkey)    return resp, nil}func main() {    listen, err := net.Listen("tcp", Address)    if err != nil {        grpclog.Fatalf("failed to listen: %v", err)    }    // TLS認證    creds, err := credentials.NewServerTLSFromFile("../../keys/server.pem", "../../keys/server.key")    if err != nil {        grpclog.Fatalf("Failed to generate credentials %v", err)    }    // 執行個體化grpc Server, 並開啟TLS認證    s := grpc.NewServer(grpc.Creds(creds))    // 註冊HelloService    pb.RegisterHelloServer(s, HelloService)    grpclog.Println("Listen on " + Address + " with TLS + Token")    s.Serve(listen)}

運行:

go run main.goListen on 50052 with TLS + Token

運行用戶端程式 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

參考

本系列範例程式碼

  • go-grpc-example

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.