gRPC四种模式、认证和授权实战演示
前言
上一篇對(duì)gRPC進(jìn)行簡(jiǎn)單介紹,并通過示例體驗(yàn)了一下開發(fā)過程。接下來說說實(shí)際開發(fā)常用功能,如:gRPC的四種模式、gRPC集成JWT做認(rèn)證和授權(quán)等。
正文
1. gRPC四種模式服務(wù)
以下案例演示,服務(wù)端用微軟提供的模板創(chuàng)建,客戶端使用Winform程序演示,基于.NetCore3.1版本。具體創(chuàng)建步驟在上一篇說的很細(xì)了(gRPC趁現(xiàn)在還沒大火,搶先了解一下),接下來就直接搞重點(diǎn);這里就模仿一個(gè)學(xué)生服務(wù),包含增、刪、改、查方法,下面是用到的proto文件的全部?jī)?nèi)容,后續(xù)的實(shí)例就單獨(dú)標(biāo)出重點(diǎn)即可。
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; } //?添加學(xué)生時(shí)傳遞的類型 message?AddStudentRequest{Student?student=1;} //?查詢學(xué)生時(shí)傳遞的類型 message?QueryStudentRequest {string?UserName=1; } //?查詢?nèi)繉W(xué)生,沒有條件,但也需要一個(gè)空的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; } //?約定需要提供的服務(wù)方法 service?StudentService{rpc?GetToken(TokenRequest)?returns?(TokenResponse);//?簡(jiǎn)單模式,查詢r(jià)pc?GetStudentByUserName(QueryStudentRequest)?returns?(StudentResponse);//?服務(wù)端流模式rpc?GetAllStudent(QueryAllStudentRequest)?returns?(stream?StudentResponse);//?客戶端流模式rpc?UploadImg(stream?UploadImgRequest)?returns?(CommonResponse);//?雙向流模式rpc?AddManyStudents(stream?AddStudentRequest)?returns?(stream?StudentResponse); }整體的項(xiàng)目結(jié)構(gòu)如下:
1.1 簡(jiǎn)單模式
和現(xiàn)在http方式類似:客戶端發(fā)出單個(gè)請(qǐng)求,服務(wù)端返回單個(gè)響應(yīng)。
關(guān)于簡(jiǎn)單模式,請(qǐng)求參數(shù)和返回參數(shù)都是一般message類型,在上一篇中演示的模式就是簡(jiǎn)單模式,歸納如下步驟;
服務(wù)端
增加一個(gè)student.proto文件,在文件中定義服務(wù),編譯自動(dòng)生成對(duì)應(yīng)代碼
定義服務(wù)格式:
rpc 方法名(請(qǐng)求類型) returns (返回類型);
新建StudentDemoService類,繼承生成的代碼類,開始寫業(yè)務(wù)
在Startup文件中將服務(wù)方法暴露出去(這里寫一次即可,后續(xù)就不重復(fù)說了)
到這服務(wù)端就寫完啦,其實(shí)和原來寫WebApi接口一樣便捷。
客戶端
使用Winform的形式舉例演示客戶端,在創(chuàng)建項(xiàng)目時(shí),直接選擇Winform模板即可,簡(jiǎn)單設(shè)計(jì)了一下界面,如下:
引入對(duì)應(yīng)的包,將服務(wù)端的proto文件都拷過來(服務(wù)端和客戶端proto文件一致)
如果編譯沒自動(dòng)生成代碼,需要檢查是否引入對(duì)應(yīng)的包,是否設(shè)置了student.proto文件的屬性,如果這塊還不了解,點(diǎn)這里(gRPC趁現(xiàn)在還沒大火,搶先了解一下)先熟悉以下開發(fā)過程。
在winform設(shè)計(jì)模式下,雙擊按鈕增加點(diǎn)擊事件,開始寫業(yè)務(wù)邏輯
運(yùn)行看效果
先運(yùn)行服務(wù)端,在運(yùn)行客戶端,輸入條件,點(diǎn)擊簡(jiǎn)單模式按鈕,效果如下:
這里查不到數(shù)據(jù),客戶端程序報(bào)異常(別罵我代碼寫的不嚴(yán)謹(jǐn),小伙伴處理一下就好啦)
1.2 服務(wù)端流模式
客戶端發(fā)起一個(gè)請(qǐng)求到服務(wù)端,服務(wù)端返回連續(xù)的數(shù)據(jù)流;一般用在服務(wù)端分批返回?cái)?shù)據(jù)的情況,客戶端能持續(xù)接收服務(wù)端的數(shù)據(jù)。
服務(wù)端
在student.proto文件中增加服務(wù),編譯自動(dòng)生成代碼
定義服務(wù)格式:
rpc 方法名(請(qǐng)求類型) returns (stream 返回類型);
在StudentDemoService類中,重寫方法寫業(yè)務(wù)邏輯代碼
注意點(diǎn):
就算請(qǐng)求不需要參數(shù),也需要一個(gè)空的message類型;
這里返回的數(shù)據(jù)可以分批發(fā)送,復(fù)用連接,提高效率;
客戶端
student.proto文件保證和服務(wù)端一樣同步添加相應(yīng)的內(nèi)容
這里就不截圖了,小伙伴可以通過拷貝或是引用的方式保證文件一樣就行啦
在winform設(shè)計(jì)模式下,雙擊服務(wù)端流模式按鈕增加點(diǎn)擊事件,開始寫業(yè)務(wù)邏輯
運(yùn)行看效果
先運(yùn)行服務(wù)端,在運(yùn)行客戶端,點(diǎn)擊服務(wù)端流模式按鈕,效果如下:
1.3 客戶端流模式
客戶端將連續(xù)的數(shù)據(jù)流發(fā)送到服務(wù)端,服務(wù)端返回一個(gè)響應(yīng);用在客戶端發(fā)送多次請(qǐng)求到服務(wù)端情況,如分段上傳圖片場(chǎng)景等。
服務(wù)端
在student.proto文件中增加服務(wù),編譯自動(dòng)生成代碼
定義服務(wù)格式:
rpc 方法名(stream 請(qǐng)求類型) returns (返回類型);
在StudentDemoService類中,重寫方法寫業(yè)務(wù)邏輯代碼
客戶端
student.proto文件保證和服務(wù)端一樣同步添加相應(yīng)的內(nèi)容
這里就不截圖了,小伙伴可以通過拷貝或是引用的方式保證文件一樣就行啦。
在winform設(shè)計(jì)模式下,雙擊客戶端流模式按鈕增加點(diǎn)擊事件,開始寫業(yè)務(wù)邏輯。代碼稍多,不截圖了,不然圖片大要失真,直接上代碼吧。
private?async?void?btn_client_Click(object?sender,?EventArgs?e) {//?用于存放選擇的文件路徑string?filePath?=?string.Empty;//?打開文件選擇對(duì)話框if?(this.openFileDialog1.ShowDialog()?==?DialogResult.OK){filePath?=?this.openFileDialog1.FileName;}if(string.IsNullOrEmpty(filePath)){this.txt_result.Text?=?"請(qǐng)選擇文件";return;}//1、創(chuàng)建grpc客戶端using?var?channel?=?GrpcChannel.ForAddress("https://localhost:5001");var?grpcClient?=?new?StudentService.StudentServiceClient(channel);//2、讀取選擇的文件FileStream?fileStream?=?File.OpenRead(filePath);//3、通過客戶端請(qǐng)求流將文件流發(fā)送的服務(wù)端using?var?call?=?grpcClient.UploadImg();var?clientStream?=?call.RequestStream;//4、循環(huán)發(fā)送,指定發(fā)送完文件while(true){//?一次最多發(fā)送1024字節(jié)byte[]?buffer?=?new?byte[1024];int?nRead?=?await?fileStream.ReadAsync(buffer,?0,?buffer.Length);//?直到讀不到數(shù)據(jù)為止,即文件已經(jīng)發(fā)送完成,即退出發(fā)送if(nRead==0){break;}//?5、將每次讀取到的文件流通過客戶端流發(fā)送到服務(wù)端await?clientStream.WriteAsync(new?UploadImgRequest?{?Data?=?ByteString.CopyFrom(buffer)?});}//?6、發(fā)送完成之后,告訴服務(wù)端發(fā)送完成await?clientStream.CompleteAsync();//?7、接收返回結(jié)果,并顯示在文本框中var?res?=?await?call.ResponseAsync;this.txt_result.Text?=?$"上傳返回Code:{res.Code},Msg:{res.Msg}"; }運(yùn)行看效果
先運(yùn)行服務(wù)端,在運(yùn)行客戶端,點(diǎn)擊客戶端流模式按鈕,效果如下:
在彈框中選擇一個(gè)jpg的圖片(因?yàn)榉奖阊菔?#xff0c;服務(wù)端固定寫為jpg了),如下:
選擇完圖片就開始上傳了,如下:
是不是已經(jīng)感覺到gRPC的優(yōu)點(diǎn)了,數(shù)據(jù)傳輸量及方式有沒有先進(jìn)一點(diǎn)。
1.4 雙向流模式
雙向流就是服務(wù)端流和客戶端流的整合,請(qǐng)求和返回都可以通過流的方式交互。
服務(wù)端
在student.proto文件中增加服務(wù),編譯自動(dòng)生成代碼
定義服務(wù)格式:
rpc 方法名(stream 請(qǐng)求類型) returns (stream 返回類型);
在StudentDemoService類中,重寫方法寫業(yè)務(wù)邏輯代碼
客戶端
student.proto文件保證和服務(wù)端一樣同步添加相應(yīng)的內(nèi)容
這里就不截圖了,小伙伴可以通過拷貝或是引用的方式保證文件一樣就行啦
在winform設(shè)計(jì)模式下,雙擊雙向流模式按鈕增加點(diǎn)擊事件,開始寫業(yè)務(wù)邏輯。
運(yùn)行看效果
先運(yùn)行服務(wù)端,在運(yùn)行客戶端,點(diǎn)擊雙向流模式按鈕,效果如下:
點(diǎn)擊服務(wù)端流按鈕查看全部數(shù),看看是否添加成功:
gRPC的四種模式就簡(jiǎn)單介紹這么多,小伙伴可以根據(jù)提供的思路應(yīng)用到項(xiàng)目中。在演示案例中是不是感受到gRPC相比WebApi有更多的選擇和優(yōu)勢(shì),另外通過服務(wù)端的控制臺(tái)可以看到,交互使用的是HTTP/2協(xié)議,小伙伴感興趣可以去了解一下:
2. gRPC集成JWT認(rèn)證
和WebAPI一樣,如果提供的服務(wù)接口“裸奔”,那么風(fēng)險(xiǎn)是很大的;關(guān)于這點(diǎn),之前針對(duì)WebApi認(rèn)證和授權(quán)分享了兩篇文章,傳送門在這(跟我一起學(xué).NetCore之WebApi接口裸奔有風(fēng)險(xiǎn)(Jwt)、跟我一起學(xué).NetCore之熟悉的接口權(quán)限驗(yàn)證不能少(Jwt))。
其實(shí)gRPC集成JWT做認(rèn)證授權(quán),和原來WebApi集成方式差不多一樣,太細(xì)節(jié)的描述小伙伴可以查閱上面兩篇文章;接下來的需求目的就是把上面提供的服務(wù)保護(hù)起來,只有認(rèn)證通過才能調(diào)用。
2.1 引入Jwt相關(guān)包,注冊(cè)服務(wù),中間件管道增加認(rèn)證流程
在gRPC服務(wù)端項(xiàng)目中引入Jwt相關(guān)包
Microsoft.AspNetCore.Authentication.JwtBearer
在Startup文件中注冊(cè)相關(guān)服務(wù)
在Startup文件中增加認(rèn)證流程
在服務(wù)上增加Authorize特性標(biāo)識(shí)
運(yùn)行看效果:
通過調(diào)用結(jié)果得知,現(xiàn)在提供的gRPC服務(wù)已經(jīng)受到保護(hù),需要持有對(duì)應(yīng)身份的請(qǐng)求才能訪問,所以接下來就需要服務(wù)端提供一個(gè)獲取身份Token的方法。
2.2 服務(wù)端增加獲取Token的服務(wù)方法
服務(wù)端增加獲取Token的服務(wù)方法
現(xiàn)在student.proto文件中增加獲取Token的相關(guān)約定,編譯自動(dòng)生成對(duì)應(yīng)代碼,如下:
重寫方法,編寫獲取Token的邏輯,如下:
生成token的核心邏輯為方法GenerateToken,如下:
到這,服務(wù)端生成Token的方法就搞定了,接下開始讓客戶端獲取并使用即可。
2.3 客戶端獲取Token并使用
確保student.proto文件內(nèi)容和服務(wù)端的一致,然后編譯自動(dòng)生成代碼。
這里就不截圖了,小伙伴可以通過拷貝或是引用的方式保證文件一樣就行啦
這里將服務(wù)端流模式的按鈕復(fù)制一個(gè)出來,在其點(diǎn)擊事件中增加帶Token的邏輯
獲取Token的邏輯就是簡(jiǎn)單的調(diào)用服務(wù)端的方法,如下:
這樣就完成Jwt的集成了,服務(wù)端、客戶端都運(yùn)行起來看一下:
到這里,gRPC集成Jwt做認(rèn)證的全部演示就完成了,除了調(diào)用方式和客戶端傳遞Token的方式不一樣,其他的都和WebApi使用方式一樣。
重點(diǎn):這里gRPC可以通過Metadata進(jìn)行傳遞數(shù)據(jù),和之前WebApi的請(qǐng)求頭很像,可以根據(jù)自己需求進(jìn)行任意封裝傳遞。
3. gRPC權(quán)限驗(yàn)證思路提一下
上面只是進(jìn)行了認(rèn)證,還沒有對(duì)服務(wù)方法權(quán)限進(jìn)行管控,只要認(rèn)證通過就能調(diào)用全部服務(wù)方法;在實(shí)際應(yīng)用場(chǎng)景中更希望的是分配啥權(quán)限才能調(diào)用對(duì)應(yīng)的服務(wù),所以權(quán)限管控少不了。
gRPC的權(quán)限管控和WebApi的管控方式一樣,同樣可以使用策略的方式進(jìn)行權(quán)限驗(yàn)證。gRPC同樣能獲取到請(qǐng)求方法的Url(包名.服務(wù)名.方法名),這樣就可以以這種規(guī)則進(jìn)行權(quán)限配置,然后驗(yàn)證即可。詳細(xì)步驟可以參考跟我一起學(xué).NetCore之熟悉的接口權(quán)限驗(yàn)證不能少(Jwt),接下來就來說說主要步驟:
3.1 使用動(dòng)態(tài)權(quán)限策略形式
增加一個(gè)PermissionRequirement.cs文件,如下:
增加一個(gè)PermissionHandler.cs文件,集成自AuthorizationHandler,然后重寫處理方法,核心代碼如下:
Startup.cs文件中注冊(cè)相關(guān)服務(wù),如下:
在Authorize特性中傳遞對(duì)應(yīng)的策略名稱,如下:
這里模擬配置權(quán)限,在獲取token方法中內(nèi)置幾條對(duì)應(yīng)用戶的權(quán)限數(shù)據(jù)
運(yùn)行看效果,如下:
最后驗(yàn)證成功就正常返回結(jié)果,如果驗(yàn)證不成功就返回失敗,客戶端就報(bào)異常,如下:
源代碼地址:https://gitee.com/CodeZoe/g-rpc/tree/master
后續(xù)會(huì)把其他代碼也整理到碼云上。
總結(jié)
關(guān)于gRPC實(shí)際應(yīng)用場(chǎng)景常用的功能就先說到這吧,以上案例演示只是提供思路,小伙伴使用時(shí)可以根據(jù)對(duì)應(yīng)的需求進(jìn)行擴(kuò)展和處理。
既然聊到了服務(wù)間通信,分布式事務(wù)肯定是避不開的,下一篇開始說說分布式事務(wù)相關(guān)的點(diǎn)。
一個(gè)被程序搞丑的帥小伙,關(guān)注"Code綜藝圈",和我一起學(xué)~~~
總結(jié)
以上是生活随笔為你收集整理的gRPC四种模式、认证和授权实战演示的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: .NET 6 即将到来的新特性 — 隐式
- 下一篇: windows 服务实现定时任务调度