Golang gRPC实践 连载四 gRPC认证

Golang gRPC实践 连载四 gRPC认证,第1张

概述gRPC 默认提供了两种认证方式: 基于SSL/TLS认证方式 远程调用认证方式 两种方式可以混合使用 TLS认证示例 这里直接扩展hello项目,实现TLS认证机制 首先需要准备证书,在hello目录新建keys目录用于存放证书文件。 证书制作 制作私钥 (.key) # Key considerations for algorithm "RSA" ≥ 2048-bitopenssl genr

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 -outserver.pem -days3650
自定义信息
-----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 []:[email protected]
目录结构
$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,"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,opts...)    if err != nil {        grpclog.Fatalln(err)    }    defer conn.Close()    // 初始化客户端    c := pb.NewHelloClIEnt(conn)    // 调用方法    reqBody := new(pb.HelloRequest)    reqBody.name = "gRPC"    r,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,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,"Token认证信息无效: appID=%s,appkey=%s",appID,appkey)    }    resp := new(pb.HelloReply)    resp.Message = fmt.Sprintf("Hello %s.\nToken info: appID=%s,in.name,appkey)    return resp,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

总结

以上是内存溢出为你收集整理的Golang gRPC实践 连载四 gRPC认证全部内容,希望文章能够帮你解决Golang gRPC实践 连载四 gRPC认证所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1213815.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-04
下一篇 2022-06-04

发表评论

登录后才能评论

评论列表(0条)

保存