gRPC使用SSL实现加密通讯

 grpc默认实现了基于证书的SSL加密通讯,使用中需要注意以下事项。

  • 在Windows上开发,首先安装 OpenSSL,将OpenSSL.exe的路径添加到环境变量中。

  • 通过以下样例脚本生成通讯中所需要的服务端和客户端证书,其中需要特别注意的是,Generate server signing reques中的CN=KEKYK字段,如果是本机测试,使用本机名称。如果是真实环境,使用域名。因为客户端必须通过机器名或域名访问该服务。

生成服务端和客户端证书

    通过以下脚本生成服务端和客户端证书。脚本中命令的含义,详见博客中的另一篇文章《OpenSSL 生成服务器及客户端证书》。   

@echo off

cd /d %~dp0

set OPENSSL_CONF=C:\Program Files\OpenSSL-Win64\bin\openssl.cfg  

echo Generate CA key:
openssl genrsa -passout pass:1111 -des3 -out ca.key 4096

echo Generate CA certificate:
openssl req -passin pass:1111 -new -x509 -days 365 -key ca.key -out ca.crt -subj  "/C=CN/ST=CA/L=Cupertino/O=YourCompany/OU=YourApp/CN=MyRootCA"

echo Generate server key:
openssl genrsa -passout pass:1111 -des3 -out server.key 4096

echo Generate server signing request:
openssl req -passin pass:1111 -new -key server.key -out server.csr -subj  "/C=CN/ST=CA/L=Cupertino/O=YourCompany/OU=YourApp/CN=localhost"

echo Self-sign server certificate:
openssl x509 -req -passin pass:1111 -days 365 -in server.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out server.crt

echo Remove passphrase from server key:
openssl rsa -passin pass:1111 -in server.key -out server.key

echo Generate client key
openssl genrsa -passout pass:1111 -des3 -out client.key 4096

echo Generate client signing request:
openssl req -passin pass:1111 -new -key client.key -out client.csr -subj  "/C=CN/ST=CA/L=Cupertino/O=YourCompany/OU=YourApp/CN=FengJun"

echo Self-sign client certificate:
openssl x509 -passin pass:1111 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -set_serial 01 -out client.crt

echo Remove passphrase from client key:
openssl rsa -passin pass:1111 -in client.key -out client.key

pause

    脚本的执行结果:

 

使用SSL改进博客中《.NET使用gRPC入门教程》中的演示样例。

基于SSL的服务端

using Grpc.Core;
using GrpcLibrary;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading.Tasks;

namespace GrpcServer
{
    class GrpcImpl : GrpcService.GrpcServiceBase
    {
        // 实现SayHello方法
        public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
        {
            return Task.FromResult(new HelloReply { Message = "Hello " + request.Name });
        }
    }
    class Program
    {
        const int Port = 9007;
        public static void Main(string[] args)
        {
            var cacert = File.ReadAllText(path + "ca.crt");
            var servercert = File.ReadAllText(path + "server.crt");
            var serverkey = File.ReadAllText(path + "server.key");
            var keypair = new KeyCertificatePair(servercert, serverkey);
            var sslCredentials = new SslServerCredentials(new List<KeyCertificatePair>() { keypair }, cacert, false);

            Server server = new Server
            {
                Services = { GrpcService.BindService(new GrpcImpl()) },
                Ports = { new ServerPort("localhost", Port, sslCredentials) }
            };
            server.Start();

            Console.WriteLine("GrpcService server listening on port " + Port);
            Console.WriteLine("任意键退出...");
            Console.ReadKey();

            server.ShutdownAsync().Wait();
        }
    }
}

基于SSL的客户端

using Grpc.Core;
using GrpcLibrary;
using System;
using System.IO;

namespace GrpcClient
{
    class Program
    {
        static void Main(string[] args)
        {
            var cacert = File.ReadAllText(path + "ca.crt");
            var clientcert = File.ReadAllText(path + "client.crt");
            var clientkey = File.ReadAllText(path + "client.key");
            var ssl = new SslCredentials(cacert, new KeyCertificatePair(clientcert, clientkey));

            Channel channel = new Channel("localhost:9007", ssl);

            var client = new GrpcService.GrpcServiceClient(channel);
            var reply = client.SayHello(new HelloRequest { Name = "April" });
            Console.WriteLine("来自" + reply.Message);

            channel.ShutdownAsync().Wait();
            Console.WriteLine("任意键退出...");
            Console.ReadKey();
        }
    }
}

执行结果

 

gRPC 中,通过使用 ListenableFuture 可以方便地实现异步调用。ListenableFuture 是 Guava 库提供的一个异步回调接口,可以方便地处理异步任务的结果。在 gRPC 中,客户端可以通过 ListenableFuture 发送异步请求,并在处理响应时使用回调函数。 下面是一个简单的 gRPC ListenableFuture 示例,包括客户端和服务端的实现。 1. 客户端 ```java // 创建异步 stub ManagedChannel channel = ManagedChannelBuilder.forAddress("localhost", 50051) .usePlaintext() .build(); GreeterGrpc.GreeterFutureStub stub = GreeterGrpc.newFutureStub(channel); // 构造请求 HelloRequest request = HelloRequest.newBuilder().setName("world").build(); // 发送异步请求 ListenableFuture<HelloReply> future = stub.sayHello(request); // 注册回调函数 Futures.addCallback(future, new FutureCallback<HelloReply>() { @Override public void onSuccess(HelloReply result) { // 处理响应 System.out.println(result.getMessage()); } @Override public void onFailure(Throwable t) { // 处理错误 } }); ``` 2. 服务端 ```java // 实现同步服务 public void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) { // 处理请求 String message = "Hello " + request.getName() + "!"; HelloReply reply = HelloReply.newBuilder().setMessage(message).build(); // 返回响应 responseObserver.onNext(reply); responseObserver.onCompleted(); } // 启动服务 Server server = ServerBuilder.forPort(50051) .addService(new GreeterImpl()) .build(); server.start(); ``` 在客户端的示例代码中,我们创建了一个异步的 gRPC stub,并发送了一个异步请求。在 `sayHello()` 方法中,我们返回了一个 ListenableFuture 对象,该对象表示异步请求的结果。我们通过 Futures.addCallback() 方法来注册回调函数,用于处理服务端返回的结果。当服务端处理请求完成后,会调用回调函数中的 `onSuccess()` 方法,并将结果传递给客户端。如果发生错误,则调用 `onFailure()` 方法。 在服务端的示例代码中,我们实现了一个同步的 gRPC 服务,并处理客户端的请求。当服务端收到客户端的请求后,会根据请求参数进行处理,并返回响应。 需要注意的是,gRPC ListenableFuture 是基于 Java 的 Future 接口实现的,因此也支持使用 Future 的其他方法,如 get() 方法等。同时,gRPC 也支持使用 SSL/TLS 加密通信,确保通信的安全性。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值