首页 > 其他分享 >[微服务] 为 gRPC 服务添加 JWT 认证,使用 Apifox 客户端进行测试

[微服务] 为 gRPC 服务添加 JWT 认证,使用 Apifox 客户端进行测试

时间:2024-11-22 15:42:11浏览次数:1  
标签:服务 string gRPC JWT new using Apifox message

gRPC 测试客户端

Apifox = Postman + Swagger + Mock + JMeter
https://apifox.com/

 

为何使用 gRPC?

相较于 REST 使用 gRPC 服务具有以下优势:

性能方面

  • 高效的通信协议

gRPC 基于 HTTP/2 协议,而 RESTful API 通常基于 HTTP/1.1。HTTP/2 支持多路复用,能在一个 TCP 连接上同时发送多个请求和响应,大大提高了通信效率,减少了连接建立和销毁的开销。
例如,在一个需要频繁交互的实时数据监控系统中,gRPC 的多路复用特性使得大量数据能够快速且并发地传输,而不会像 HTTP/1.1 那样因频繁创建连接而导致性能瓶颈。

  • 更小的消息体积

gRPC 默认使用 Protocol Buffers 作为序列化格式,它比 RESTful API 常用的 JSON 格式更加紧凑和高效。
比如传输相同的结构化数据,使用 Protocol Buffers 序列化后的字节数通常会比 JSON 少很多,这在网络传输中能显著减少数据量,提高传输速度,降低带宽消耗。

代码生成和类型安全

  • 自动代码生成

gRPC 通过.proto 文件定义服务和消息类型,然后可以使用 protobuf 编译器自动生成客户端和服务器端的代码。
这避免了手动编写大量的序列化和反序列化代码,减少了开发工作量和出错的可能性。
而在 RESTful API 中,通常需要使用第三方库来进行 JSON 等格式的序列化和反序列化,且代码相对更繁琐。

  • 强类型约束

由.proto 文件生成的代码具有强类型特性,在编译时就能发现类型不匹配等错误,而不是在运行时才暴露问题。
例如,如果一个函数期望接收一个整数类型的参数,传入字符串就会在编译阶段报错,有助于提高代码的稳定性和可维护性。
相比之下,RESTful API 在处理请求和响应时,对数据类型的约束相对较弱,容易出现类型错误。

服务定义和 IDL

  • 清晰的服务定义

gRPC 使用.proto 文件以接口描述语言(IDL)的形式明确定义服务的接口、方法签名、请求和响应消息结构等。
这种清晰的服务定义使得开发团队在开发客户端和服务器端时能更好地协同工作,避免了因对接口理解不一致而产生的问题。
而 RESTful API 的接口定义通常分散在代码和文档中,不够集中和明确。

  • 跨语言支持

由于.proto 文件是与语言无关的,gRPC 支持多种编程语言,方便不同语言编写的客户端和服务器端之间进行通信。
例如,可以用 C# 编写 gRPC 服务器,同时用 Python 或 Java 编写客户端来调用该服务,这在构建多语言的分布式系统时非常有优势。
而 RESTful API 虽然也能实现跨语言调用,但在接口定义和数据格式处理上可能会因语言的不同而遇到更多兼容性问题。

流处理能力

  • 双向流支持

gRPC 支持双向流,客户端和服务器端可以同时向对方发送数据流。
例如在实时视频会议系统中,gRPC 的双向流功能可以让客户端实时上传视频数据的同时,服务器端也能及时下发其他参会者的视频数据和控制指令,实现高效的实时交互。
相比之下,RESTful API 通常以请求 - 响应模式为主,对双向流的支持相对较弱。

 

操作范例

1. 创建 gRPC 项目并添加 new proto 文件 

syntax = "proto3";
option csharp_namespace = "Todo_GrpcService.Protos";
package todo; 

/* 定义服务接口 */
service ITodoService {
    rpc NewTodo(NewTodoRequest) returns (NewTodoReply);
    rpc GetTodoList(GetTodoListRequest) returns (stream GetTodoListReply);
}

/* 定义服务 message 参数类型 */
message NewTodoRequest {
    int32 ID = 1;
    string Name = 2;
    bytes data = 3;
}
message NewTodoReply {
    bool Status = 1;
    string Message = 2;
}

message GetTodoListRequest {
}
message GetTodoListReply {
    bool Status = 1;
    string Name = 2;
}

2. 编辑项目的 Project File,开放对所有 Protobuf 文件的自动编译

<Protobuf Include="Protos\*.proto" GrpcServices="Server" />

3. 创建 new service,重载并实现 proto 接口的业务逻辑

4. 编辑项目 Program.cs 文件,将 TodoService 服务添加到路由管道

app.MapGrpcService<TodoService>();

 

如何对 gRPC 服务进行测试?

5. 使用 Apifox 测试 gRPC 服务,导入 .proto 文件

6. 运行服务进行测试

 

如何对 gRPC 集成 JWT 身份认证?

7. 项目添加 Nuget 引用 "Microsoft.AspNetCore.Authentication.JwtBearer"

8. 创建 auth.proto

syntax = "proto3";
option csharp_namespace = "Todo_GrpcService.Protos";
package auth;

/* 定义服务接口 */
service IAuth {
  rpc GetToken (AuthData) returns (AuthResult);
  rpc ConnectTest(Empty) returns (AuthSuccess);
}

/* 定义服务 message 参数类型 */
message AuthData {
    string name = 1;
    string pass = 2;
}
message AuthResult {
    int32 code = 1;
    string token = 2;
    string message = 3;
}
message Empty {
}
message AuthSuccess {
    string message = 1;
}

9. 创建 AuthService.cs

using Grpc.Core;
using Microsoft.AspNetCore.Authorization;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Todo_GrpcService.Protos;

namespace Todo_GrpcService.Services
{
    public class AuthService : IAuth.IAuthBase
    {
        public override Task<AuthResult> GetToken(AuthData request, ServerCallContext context)
        {
            Console.OutputEncoding = Encoding.UTF8;
            if (request.Name == "test_username" && request.Pass == "test_password")
            {
                var claims = new[]
                {
                    new Claim(ClaimTypes.NameIdentifier, "0"),
                    new Claim(ClaimTypes.Name, "test_username")
                };
                var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("This_Is_Lonooooooooooooooooooooooooooooooooooooooooooooooooooog_Security_Key_String"));
                var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
                var token = new JwtSecurityToken(
                    issuer: "test_jwt_issuer",
                    audience: "test_jwt_audience",
                    claims: claims,
                    notBefore: DateTime.UtcNow,
                    expires: DateTime.UtcNow.AddSeconds(10),
                    signingCredentials: creds);
                var stoken = new JwtSecurityTokenHandler().WriteToken(token);
                return Task.FromResult(new AuthResult
                {
                    Code = 1,
                    Message = "Auth Success",
                    Token = stoken
                });
            }
            return Task.FromResult(new AuthResult
            {
                Code = -1,
                Message = "Auth Failed"
            });
        }

        [Authorize]
        public override Task<AuthSuccess> ConnectTest(Empty request, ServerCallContext context)
        {
            Console.OutputEncoding = Encoding.UTF8;
            var user = context.GetHttpContext().User;
            Console.WriteLine("Connect Success");
            return Task.FromResult(new AuthSuccess
            {
                Message = "Connect Success"
            });
        }
    }
}

10. 编辑项目 Program.cs 文件,将 AuthService 添加到路由管道

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using Todo_GrpcService.Services;

namespace Todo_GrpcService
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var builder = WebApplication.CreateBuilder(args);

            /* Working for JWT */
            builder.Services.AddAuthentication(t =>
            {
                t.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                t.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            }).AddJwtBearer(t => {
                t.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidIssuer = "test_jwt_issuer",
                    ValidAudience = "test_jwt_audience",
                    IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("This_Is_Lonooooooooooooooooooooooooooooooooooooooooooooooooooog_Security_Key_String"))
                };
            });
            builder.Services.AddAuthorization();

            // Add services to the container.
            builder.Services.AddGrpc();

            var app = builder.Build();

            // Configure the HTTP request pipeline.
            app.MapGrpcService<GreeterService>();
            app.MapGrpcService<TodoService>();

            /* Working for JWT */
            app.MapGrpcService<AuthService>();
            
            app.MapGet("/", () => "Communication with gRPC endpoints must be made through a gRPC client. To learn how to create a client, visit: https://go.microsoft.com/fwlink/?linkid=2086909");
            app.Run();
        }
    }
}

11. 使用 Apifox 测试 <未认证 Case>

  • 获取 Token 失败

  •  直接访问服务失败

 12. 使用 Apifox 测试 <通过认证 Case>

  • 获取 Token 成功

  •  访问服务成功

 

参考教程

gRPC入门与实操(.NET篇)
https://www.cnblogs.com/newton/p/17033789.html

gRPC四种模式、认证和授权实战演示,必赞~~~
https://www.cnblogs.com/zoe-zyq/p/15004843.html

.Net Core gRPC入门
https://blog.csdn.net/qq_31803267/category_10082392.html

豆包 - 全能 AI 助手
https://www.doubao.com/chat/

标签:服务,string,gRPC,JWT,new,using,Apifox,message
From: https://www.cnblogs.com/jinzesudawei/p/18562611

相关文章

  • 安利一款超级好用的 Dubbo 调试工具 Apifox
    大家好啊!今天我要安利一个神器——Apifox!特别是它最近的Dubbo调试功能,简直是为我们Java开发者操碎了心啊!......
  • 安利一款好用的 gRPC 调试工具 Apifox
    各位用gRPC的小伙伴们!今天要给大家安利一个超好用的gRPC调试神器-Apifox!它对gRPC的支持真的是太友好了,让我们一起来看看~gRPC调试功能有多强?支持的调用类型描述使用场景一元调用类似HTTP请求的简单调用常规的请求-响应场景服务端流服务器端持续推送数据实时......
  • 推荐一个好用的 REST API 测试工具 Apifox
    大家好啊!今天给大家安利一个超级好用的RESTAPI测试工具——Apifox。说实话,作为一个经常和API打交道的开发者,以前总是被各种API测试和管理的问题困扰。直到遇到了Apifox,才发现原来API测试可以这么舒服!Apifox是啥?简单来说,Apifox就是一个"一站式"API开发测试工具。......
  • apifox使用小记
    1.copyascURL(cmd)之后在apifox里直接importcURL  2.调用时发生301错误通常情况下是因为有session校验存在(用户校验)。解决方案:F12里将cookie里的session取到,在apifox里全局配置 这里踩了一个坑第一次我是import了一个get请求,发送后发生301,所以我去设置了cookies......
  • 深入解析 Session、Cookie、Token 和 JWT:身份验证与会话管理的最佳实践
    深入解析Session、Cookie、Token和JWT:身份验证与会话管理的最佳实践在现代Web开发中,用户身份验证和会话管理是至关重要的部分。为了实现这些功能,开发者通常会使用Session、Cookie、Token和JWT。本文将从各个角度详细介绍这四者的概念及其应用,并探讨如何结合使用它们来实......
  • gin使用JWT验证
    packagejwtauthimport("WchimeGinSystem/conf""errors""time""github.com/golang-jwt/jwt/v5")typeMyClaimsstruct{jwt.RegisteredClaimsUserIdint64}funcCreateToken(userIdint64)......
  • Axios 拦截器示例(JWT 登录与自动刷新)
    1.安装axios首先,确保你已经安装了axios:npminstallaxios2.设置Axios拦截器importaxiosfrom'axios';//创建一个axios实例constaxiosInstance=axios.create({baseURL:'http://localhost:8000/',//后端API地址timeout:10000,//设置超时时间......
  • JWT 登录与注销示例
    1.后端(Django+DRF)实现安装依赖首先,确保安装了django-rest-framework和django-rest-framework-simplejwt:pipinstalldjangorestframeworkpipinstalldjangorestframework-simplejwt配置settings.py#settings.pyINSTALLED_APPS=[...'rest_framework'......
  • gRPC cmake Visual Studio编译安装 (全命令行)
    gRPCcmake编译安装(全命令行)重要前言:所有在引用框中的命令都不要输入!!cmake--install. #在引用框中的不要输入到命令行cmake--install.--configDebug #命令没有被引用框包裹,需要输入到命令行中0x00环境配置vs2022,git,cmake,Powershell7<管理员......
  • .net 8 实现【JWT】 十分钟领略【无状态设计】
      本文主要分为两个部分:  1、概念  2、.net8demo  第一部分主要描述所有与JWT相关的概念以及词汇,及其原理;第二部分是代码示例。  1、概念JWTjsonwebtoken是一种开放标准(RFC7519),是指定一种数据格式(json)和数据结构(header,payload,si......