GRPC开发(5)-grpc服务开发-带证书才是安全的服务

cd ~/goproject/grpcpro
项目中,server、client、protoc、cert目录都是并列的,go mod的模块是grpcpro

改造server.go

s := grpc.NewServer()
改成
creds, err := credentials.NewServerTLSFromFile("…/cert/server.crt", “…/cert/server.key”)
s := grpc.NewServer(grpc.Creds(creds))

package main
import (
        "context"
        "log"
        "net"
        pb "grpcpro/protoc"
        "google.golang.org/grpc/credentials"
        "google.golang.org/grpc"
)

const (
        addr = "127.0.0.1:50052"
)

type server struct{}

func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
        log.Printf("Received: %v", in.Name)
        return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}
func main() {
        creds, err := credentials.NewServerTLSFromFile("../cert/server.crt", "../cert/server.key")
        s := grpc.NewServer(grpc.Creds(creds))
        //s := grpc.NewServer()
        pb.RegisterHelloServer(s, &server{})

        lis, err := net.Listen("tcp", addr)
        if err != nil {
                log.Fatalf("failed to listen: %v", err)
        }
        if err := s.Serve(lis); err != nil {
                log.Fatalf("failed to serve: %v", err)
        }
}

改造client.go
之前的服务,没有证书,所以使用grpc.WithInsecure()跳过了证书验证
现在需要证书验证
方式1:
在客户端基于服务器的证书和服务器名字就可以对服务器进行验证

记得创建证书时:# openssl req -new -key server.key -subj “/CN=grpcpro1” -out server.csr
服务器名称是 grpcpro1
把conn, err := grpc.Dial(address, grpc.WithInsecure())
改成
creds, err := credentials.NewClientTLSFromFile("…/…/cert/server.crt", “grpcpro1”)
if err != nil {
log.Fatalf(“NewClientTLSFromFile: %v”, err)
}
conn, err := grpc.Dial(address, grpc.WithTransportCredentials(creds))

package main

import (
        "context"
        "log"
        "os"
        "time"
        "google.golang.org/grpc/credentials"
        pb "grpcpro/protoc"
        "google.golang.org/grpc"
)

const (
        address     = "127.0.0.1:50052"
        defaultName = "world"
)

func main() {
        // grpc.Dial负责和GRPC服务建立链接
        creds, err := credentials.NewClientTLSFromFile("../cert/server.crt", "grpcpro1")
        if err != nil {
                log.Fatalf("NewClientTLSFromFile: %v", err)
        }
        conn, err := grpc.Dial(address, grpc.WithTransportCredentials(creds))
        if err != nil {
                log.Fatalf("did not connect: %v", err)
        }
        defer conn.Close()
        // 然后NewGreeterClient函数基于已经建立的链接构造GreeterClient对象
        // 返回的client其实是一个GreeterClient接口对象,通过接口定义的方法就可以调用服务端对应的GRPC服务提供的方法。
        c := pb.NewHelloClient(conn)

        // Contact the server and print out its response.
        name := defaultName
        if len(os.Args) > 1 {
                name = os.Args[1]
        }
        //5秒超时
        ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
        defer cancel()
        r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
        if err != nil {
                log.Fatalf("could not greet: %v", err)
        }
        log.Printf("Hello: %s", r.Message)
}

上面是简单的实现。
下面是比较完整的实现
server.go
使用http的http.ListenAndServeTLS代替net.Listen

package main
import (
        "context"
        "log"
        "net/http"
        pb "grpcpro/protoc"
        "google.golang.org/grpc"
)

const (
        addr = "127.0.0.1:50052"
)

type server struct{}

func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
        log.Printf("Received: %v", in.Name)
        return &pb.HelloReply{Message: "Hello " + in.Name}, nil
}

func main() {
        s := grpc.NewServer()
        // var size = 1024 * 1024 * 1024 //1024M
        // s := grpc.NewServer(grpc.MaxMsgSize(size), grpc.MaxRecvMsgSize(size), grpc.MaxSendMsgSize(size))
        pb.RegisterHelloServer(s, &server{})
        if err:=http.ListenAndServeTLS(addr, "../cert/server.crt", "../cert/server.key",
                http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
                        s.ServeHTTP(w, r) // GRPC Server
                        return
                }),
        );err!=nil{
                panic(err)
        }
}

client改造
client应该使用生成的client证书,在客户端就基于CA证书对服务器进行证书验证
ServerName还是之前的/CN: “grpcpro1”

package main

import (
        "context"
        "log"
        "os"
        "time"
        "crypto/x509"
        "crypto/tls"
        "io/ioutil"
        "google.golang.org/grpc/credentials"
        pb "grpcpro/protoc"
        "google.golang.org/grpc"
)

const (
        address     = "127.0.0.1:50052"
        defaultName = "world"
)

func main() {

        certificate, err := tls.LoadX509KeyPair("../cert/client.crt", "../cert/client.key")
        if err != nil {
                log.Fatal(err)
        }

        certPool := x509.NewCertPool()
        ca, err := ioutil.ReadFile("../cert/ca.crt")
        if err != nil {
                log.Fatal(err)
        }
        if ok := certPool.AppendCertsFromPEM(ca); !ok {
                log.Fatal("failed to append ca certs")
        }
        creds := credentials.NewTLS(&tls.Config{
                Certificates: []tls.Certificate{certificate},
                ServerName: "grpcpro1", // NOTE: this is required!
                RootCAs: certPool,
        })



        // grpc.Dial负责和GRPC服务建立链接
        conn, err := grpc.Dial(address, grpc.WithTransportCredentials(creds))
        if err != nil {
                log.Fatalf("did not connect: %v", err)
        }
        defer conn.Close()
        // 然后NewGreeterClient函数基于已经建立的链接构造GreeterClient对象
        // 返回的client其实是一个GreeterClient接口对象,通过接口定义的方法就可以调用服务端对应的GRPC服务提供的方法。
        c := pb.NewHelloClient(conn)

        // Contact the server and print out its response.
        name := defaultName
        if len(os.Args) > 1 {
                name = os.Args[1]
        }
        //5秒超时
        ctx, cancel := context.WithTimeout(context.Background(), time.Second*5)
        defer cancel()
        r, err := c.SayHello(ctx, &pb.HelloRequest{Name: name})
        if err != nil {
                log.Fatalf("could not greet: %v", err)
        }
        log.Printf("Hello: %s", r.Message)
}

至此我们就启动了安全的GRPC服务了。否则按照之前的无证书访问,简直就是裸奔。。。

grpc-server-spring-boot-starter是一个基于Spring Boot框架的gRPC服务器的启动器。gRPC(Google Remote Procedure Call)是一种高性能的远程过程调用框架,它使用Protocol Buffers作为接口定义语言,并支持多种编程语言。 grpc-server-spring-boot-starter提供了一系列简化配置和集成的功能,使得在Spring Boot应用中启动和配置gRPC服务器变得更加容易。它提供了自动装配的功能,可以根据应用的配置自动创建和启动gRPC服务器。用户只需要在配置文件中设置相应的参数,如服务器的端口号、TLS证书等,即可完成服务器的启动配置。 在使用grpc-server-spring-boot-starter时,用户可以方便地定义服务接口和实现类。通过使用gRPC的接口定义语言(protobuf)定义接口,并生成对应的Java代码。然后,用户只需要在实现类中实现相应的接口方法即可。 在服务器启动后,grpc-server-spring-boot-starter会根据定义的接口和实现类,自动创建相应的gRPC服务,并将其注册到服务器中。当客户端发起远程调用时,服务器会根据接口定义和方法参数,将请求转发给对应的实现类,并返回执行结果给客户端。 grpc-server-spring-boot-starter还支持对gRPC服务器进行拦截器的配置。拦截器可以在请求和响应的过程中拦截和修改消息,用于实现日志记录、鉴权、性能监控等功能。 总之,grpc-server-spring-boot-starter简化了在Spring Boot应用中使用gRPC的配置和集成过程,使得开发者可以更加便捷地构建和部署gRPC服务器。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

InterestingFigure

迈克 Let's Go

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值