8

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

 2 years ago
source link: https://www.cnblogs.com/zoe-zyq/p/15004843.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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综艺圈",和我一起学~~~


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK