• gRPC四种模式、认证和授权实战演示,必赞~~~


    前言

    上一篇对gRPC进行简单介绍,并通过示例体验了一下开发过程。接下来说说实际开发常用功能,如:gRPC的四种模式、gRPC集成JWT做认证和授权等。

    正文

    1. gRPC四种模式服务

    以下案例演示,服务端用微软提供的模板创建,客户端使用Winform程序演示,基于.NetCore3.1版本。具体创建步骤在上一篇说的很细了(gRPC趁现在还没大火,抢先了解一下),接下来就直接搞重点;这里就模仿一个学生服务,包含增、删、改、查方法,下面是用到的proto文件的全部内容,后续的实例就单独标出重点即可。

    syntax = "proto3"; //指定版本
    // 定义命名空间
    option csharp_namespace = "Grpc.Server.Demo";
    // 指定包名,避免冲突
    package user;
    // 定义Student 的 message类型
    message Student {
      string UserName = 1;
      int32 Age=2;
      string addr = 3;
    }
    // 公共返回类型
    message CommonResponse{
    	int32 code =1;
    	string msg=2;
    }
    // 添加学生时传递的类型
    message AddStudentRequest{
    	Student student=1;
    
    }
    // 查询学生时传递的类型
    message QueryStudentRequest
    {
    	string UserName=1;
    }
    // 查询全部学生,没有条件,但也需要一个空的message
    message QueryAllStudentRequest
    {
    }
    // 上传图片
    message UploadImgRequest{
    	bytes data = 1;
    }
    message StudentResponse {
      Student student =1;
    }
    message TokenRequest{
    	string UserName=1;
    	string UserPwd=2;
    }
    message TokenResponse{
    	string Token =1;
    }
    // 约定需要提供的服务方法
    service StudentService{
        rpc GetToken(TokenRequest) returns (TokenResponse);
    	// 简单模式,查询
    	rpc GetStudentByUserName(QueryStudentRequest) returns (StudentResponse);
    	// 服务端流模式
    	rpc GetAllStudent(QueryAllStudentRequest) returns (stream StudentResponse);
    	// 客户端流模式
    	rpc UploadImg(stream UploadImgRequest) returns (CommonResponse);
    	// 双向流模式
    	rpc AddManyStudents(stream AddStudentRequest) returns (stream StudentResponse);
    }
    

    整体的项目结构如下:

    1.1 简单模式

    和现在http方式类似:客户端发出单个请求,服务端返回单个响应。

    关于简单模式,请求参数和返回参数都是一般message类型,在上一篇中演示的模式就是简单模式,归纳如下步骤;

    服务端

    • 增加一个student.proto文件,在文件中定义服务,编译自动生成对应代码

      定义服务格式:

      rpc 方法名(请求类型) returns (返回类型);

    • 新建StudentDemoService类,继承生成的代码类,开始写业务

    • 在Startup文件中将服务方法暴露出去(这里写一次即可,后续就不重复说了)

      到这服务端就写完啦,其实和原来写WebApi接口一样便捷。

    客户端

    使用Winform的形式举例演示客户端,在创建项目时,直接选择Winform模板即可,简单设计了一下界面,如下:

    • 引入对应的包,将服务端的proto文件都拷过来(服务端和客户端proto文件一致)

      如果编译没自动生成代码,需要检查是否引入对应的包,是否设置了student.proto文件的属性,如果这块还不了解,点这里(gRPC趁现在还没大火,抢先了解一下)先熟悉以下开发过程。

    • 在winform设计模式下,双击按钮增加点击事件,开始写业务逻辑

    • 运行看效果

      先运行服务端,在运行客户端,输入条件,点击简单模式按钮,效果如下:

      这里查不到数据,客户端程序报异常(别骂我代码写的不严谨,小伙伴处理一下就好啦)

    1.2 服务端流模式

    客户端发起一个请求到服务端,服务端返回连续的数据流;一般用在服务端分批返回数据的情况,客户端能持续接收服务端的数据。

    服务端

    • 在student.proto文件中增加服务,编译自动生成代码

      定义服务格式:

      rpc 方法名(请求类型) returns (stream 返回类型);

    • 在StudentDemoService类中,重写方法写业务逻辑代码

      注意点:

      1. 就算请求不需要参数,也需要一个空的message类型;
      2. 这里返回的数据可以分批发送,复用连接,提高效率;

    客户端

    • student.proto文件保证和服务端一样同步添加相应的内容

      这里就不截图了,小伙伴可以通过拷贝或是引用的方式保证文件一样就行啦

    • 在winform设计模式下,双击服务端流模式按钮增加点击事件,开始写业务逻辑

    • 运行看效果

      先运行服务端,在运行客户端,点击服务端流模式按钮,效果如下:

    1.3 客户端流模式

    客户端将连续的数据流发送到服务端,服务端返回一个响应;用在客户端发送多次请求到服务端情况,如分段上传图片场景等。

    服务端

    • 在student.proto文件中增加服务,编译自动生成代码

      定义服务格式:

      rpc 方法名(stream 请求类型) returns (返回类型);

    • 在StudentDemoService类中,重写方法写业务逻辑代码

    客户端

    • student.proto文件保证和服务端一样同步添加相应的内容

      这里就不截图了,小伙伴可以通过拷贝或是引用的方式保证文件一样就行啦。

    • 在winform设计模式下,双击客户端流模式按钮增加点击事件,开始写业务逻辑。代码稍多,不截图了,不然图片大要失真,直接上代码吧。

      private async void btn_client_Click(object sender, EventArgs e)
      {
          // 用于存放选择的文件路径
          string filePath = string.Empty;
          // 打开文件选择对话框
          if (this.openFileDialog1.ShowDialog() == DialogResult.OK)
          {
              filePath = this.openFileDialog1.FileName;
          }
          if(string.IsNullOrEmpty(filePath))
          {
              this.txt_result.Text = "请选择文件";
              return;
          }
          //1、创建grpc客户端
          using var channel = GrpcChannel.ForAddress("https://localhost:5001");
          var grpcClient = new StudentService.StudentServiceClient(channel);
          //2、读取选择的文件
          FileStream fileStream = File.OpenRead(filePath);
          //3、通过客户端请求流将文件流发送的服务端
          using var call = grpcClient.UploadImg();
          var clientStream = call.RequestStream;
          //4、循环发送,指定发送完文件
          while(true)
          {
              // 一次最多发送1024字节
              byte[] buffer = new byte[1024];
              int nRead = await fileStream.ReadAsync(buffer, 0, buffer.Length);
              // 直到读不到数据为止,即文件已经发送完成,即退出发送
              if(nRead==0)
              {
                  break;
              }
              // 5、将每次读取到的文件流通过客户端流发送到服务端
              await clientStream.WriteAsync(new UploadImgRequest { Data = ByteString.CopyFrom(buffer) });
          }
          // 6、发送完成之后,告诉服务端发送完成
          await clientStream.CompleteAsync();
          // 7、接收返回结果,并显示在文本框中
          var res = await call.ResponseAsync;
          this.txt_result.Text = $"上传返回Code:{res.Code},Msg:{res.Msg}";
      }
      
    • 运行看效果

      先运行服务端,在运行客户端,点击客户端流模式按钮,效果如下:

      在弹框中选择一个jpg的图片(因为方便演示,服务端固定写为jpg了),如下:

      选择完图片就开始上传了,如下:

      是不是已经感觉到gRPC的优点了,数据传输量及方式有没有先进一点。

    1.4 双向流模式

    双向流就是服务端流和客户端流的整合,请求和返回都可以通过流的方式交互。

    服务端

    • 在student.proto文件中增加服务,编译自动生成代码

      定义服务格式:

      rpc 方法名(stream 请求类型) returns (stream 返回类型);

    • 在StudentDemoService类中,重写方法写业务逻辑代码

    客户端

    • student.proto文件保证和服务端一样同步添加相应的内容

      这里就不截图了,小伙伴可以通过拷贝或是引用的方式保证文件一样就行啦

    • 在winform设计模式下,双击双向流模式按钮增加点击事件,开始写业务逻辑。

    • 运行看效果

      先运行服务端,在运行客户端,点击双向流模式按钮,效果如下:

      点击服务端流按钮查看全部数,看看是否添加成功:

    gRPC的四种模式就简单介绍这么多,小伙伴可以根据提供的思路应用到项目中。 在演示案例中是不是感受到gRPC相比WebApi有更多的选择和优势,另外通过服务端的控制台可以看到,交互使用的是HTTP/2协议,小伙伴感兴趣可以去了解一下:

    2. gRPC集成JWT认证

    和WebAPI一样,如果提供的服务接口“裸奔”,那么风险是很大的;关于这点,之前针对WebApi认证和授权分享了两篇文章,传送门在这(跟我一起学.NetCore之WebApi接口裸奔有风险(Jwt)跟我一起学.NetCore之熟悉的接口权限验证不能少(Jwt))。

    其实gRPC集成JWT做认证授权,和原来WebApi集成方式差不多一样,太细节的描述小伙伴可以查阅上面两篇文章;接下来的需求目的就是把上面提供的服务保护起来,只有认证通过才能调用。

    2.1 引入Jwt相关包,注册服务,中间件管道增加认证流程
    • 在gRPC服务端项目中引入Jwt相关包

      Microsoft.AspNetCore.Authentication.JwtBearer

    • 在Startup文件中注册相关服务

    • 在Startup文件中增加认证流程

    • 在服务上增加Authorize特性标识

      运行看效果:

      通过调用结果得知,现在提供的gRPC服务已经受到保护,需要持有对应身份的请求才能访问,所以接下来就需要服务端提供一个获取身份Token的方法。

    2.2 服务端增加获取Token的服务方法
    • 服务端增加获取Token的服务方法

      现在student.proto文件中增加获取Token的相关约定,编译自动生成对应代码,如下:

      重写方法,编写获取Token的逻辑,如下:

      生成token的核心逻辑为方法GenerateToken,如下:

      到这,服务端生成Token的方法就搞定了,接下开始让客户端获取并使用即可。

    2.3 客户端获取Token并使用
    • 确保student.proto文件内容和服务端的一致,然后编译自动生成代码。

      这里就不截图了,小伙伴可以通过拷贝或是引用的方式保证文件一样就行啦

    • 这里将服务端流模式的按钮复制一个出来,在其点击事件中增加带Token的逻辑

      获取Token的逻辑就是简单的调用服务端的方法,如下:

      这样就完成Jwt的集成了,服务端、客户端都运行起来看一下:

    到这里,gRPC集成Jwt做认证的全部演示就完成了,除了调用方式和客户端传递Token的方式不一样,其他的都和WebApi使用方式一样。

    重点:这里gRPC可以通过Metadata进行传递数据,和之前WebApi的请求头很像,可以根据自己需求进行任意封装传递。

    3. gRPC权限验证思路提一下

    上面只是进行了认证,还没有对服务方法权限进行管控,只要认证通过就能调用全部服务方法;在实际应用场景中更希望的是分配啥权限才能调用对应的服务,所以权限管控少不了。

    gRPC的权限管控和WebApi的管控方式一样,同样可以使用策略的方式进行权限验证。gRPC同样能获取到请求方法的Url(包名.服务名.方法名),这样就可以以这种规则进行权限配置,然后验证即可。详细步骤可以参考跟我一起学.NetCore之熟悉的接口权限验证不能少(Jwt),接下来就来说说主要步骤:

    3.1 使用动态权限策略形式
    • 增加一个PermissionRequirement.cs文件,如下:

    • 增加一个PermissionHandler.cs文件,集成自AuthorizationHandler,然后重写处理方法,核心代码如下:

    • Startup.cs文件中注册相关服务,如下:

    • 在Authorize特性中传递对应的策略名称,如下:

    • 这里模拟配置权限,在获取token方法中内置几条对应用户的权限数据

    • 运行看效果,如下:

      最后验证成功就正常返回结果,如果验证不成功就返回失败,客户端就报异常,如下:

    源代码地址:https://gitee.com/CodeZoe/g-rpc/tree/master

    后续会把其他代码也整理到码云上。

    总结

    关于gRPC实际应用场景常用的功能就先说到这吧,以上案例演示只是提供思路,小伙伴使用时可以根据对应的需求进行扩展和处理。

    既然聊到了服务间通信,分布式事务肯定是避不开的,下一篇开始说说分布式事务相关的点。

    一个被程序搞丑的帅小伙,关注"Code综艺圈",和我一起学~~~

  • 相关阅读:
    【0】认识 神舟王STM32
    【0】STM32 型号 命名 规则
    【1】STM32 Debug in RAM 在RAM中调试STM32 !!!
    【转】3个普通IO识别22个按键试验
    状态机思路在单片机程序设计中的应用
    关于iOS中UIView类视图的圆角
    静态库.a
    cocoapods的安装和使用,遇到的错误
    网络请求后关于刷新界面UI的问题
    UITextField限制字数方法
  • 原文地址:https://www.cnblogs.com/zoe-zyq/p/15004843.html
Copyright © 2020-2023  润新知