前言
随着. net core3.0 的正式发布, gRPC 服务被集成到了 VS2019. 本文主要演示如何对 gRPC 的服务进行认证授权.
分析
目前. net core 使用最广的认证授权组件是基于 OAuth2.0 协议的 IdentityServer4. 而 gRPC 可以与 ASP.NET Core Authentication 一起使用来实现认证授权功能. 本文将创建 3 个应用程序来完成 gRPC 的认证授权演示过程.
步骤
Ids4.Server
1. 创建一个. net core 的 webapi
2.nuget 引用最新的 IdentityServer4 的包
<PackageReference Include="IdentityServer4" Version="3.0.1" />
IdentityServer4 相关配置, 因为是演示所以很简单, 生产场景大家根据实际情况配置.
- namespace Ids4.Server
- {
- public class Config
- {
- public static IEnumerable<IdentityResource> GetIdentityResources()
- {
- return new List<IdentityResource>
- {
- new IdentityResources.OpenId(),
- new IdentityResources.Profile(),
- new IdentityResources.Email(),
- };
- }
- public static IEnumerable<ApiResource> GetApis()
- {
- return new List<ApiResource>
- {
- new ApiResource("api", "Demo API")
- {
- ApiSecrets = { new Secret("secret".Sha256()) }
- }
- };
- }
- public static IEnumerable<Client> GetClients()
- {
- return new List<Client>
- {
- new Client
- {
- ClientId = "client",
- ClientSecrets = { new Secret("secret".Sha256()) },
- AllowedGrantTypes = GrantTypes.ClientCredentials,
- AllowedScopes = { "api" },
- },
- };
- }
- }
- }
4. startup.cs 注入服务
- services.AddIdentityServer().AddInMemoryApiResources(Config.GetApis())
- .AddInMemoryIdentityResources(Config.GetIdentityResources())
- .AddInMemoryClients(Config.GetClients())
- .AddDeveloperSigningCredential(persistKey: false);
5. startup.cs 配置 http 请求管道
App.UseIdentityServer();
6. 启动服务, 使用 PostMan 进行调试, 有返回结果表示服务创建成功
- POST /connect/token HTTP/1.1
- Host: localhost:5000
- Content-Type: application/x-www-form-urlencoded
- grant_type=client_credentials&client_id=client1&client_secret=secret
- {
- "access_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IlVyMmxuM2EwNGhWaGdDdWZTVTNtZVEiLCJ0eXAiOiJhdCtqd3QifQ.eyJuYmYiOjE1NzEzMDkwMTMsImV4cCI6MTU3MTMxMjYxMywiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MDAwIiwiYXVkIjoiYXBpIiwiY2xpZW50X2lkIjoiY2xpZW50Iiwic2NvcGUiOlsiYXBpIl19.X4pg9_FbPbWZl814XC0NYWTslfhMG4aXWEyXLrXhIojPJaL7Qvq9ieDF4S7x0psRcClwbwCg81hTrG3j2Cmcl0nzj_Ic7UY8MfN0dvAuy_fJdUf76TX0oOpir3SxgC8gnfaKyEoWmmbIyvwicWbKp9PP-EeTxG6-oMYn6PO22cwRVHDD28ZdEAq2DEkATOh9XPavoi9vGZhPQ1nviKL1K6tcYUGXSQbhWI9ISEqnTHqMX1xA_gcDIAplGvquXmtXdgyTsRoGolEtzDAYVH4sGUb1SpYx2nc8bgl6Qw27fhe0Uy9MR70kQMcEkCTdXLivjYjkuI9_quUyJHzdi5KgnQ",
- "expires_in": 3600,
- "token_type": "Bearer",
- "scope": "api"
- }
本篇不对 IdentityServer4 做更多的讲解, 大家可以参考官方文档了解更多.
Grpc.Server
1. 使用 vs2019 创建 gRPC 服务端.
2. 不用做任何更改, 直接使用默认创建的 gRPC 服务
Grpc.Client
1. 创建一个控制台程序
2. 引入 nuget 安装包
- <PackageReference Include="Google.Protobuf" Version="3.10.0" />
- <PackageReference Include="Grpc.Net.Client" Version="2.23.2" />
- <PackageReference Include="Grpc.Tools" Version="2.24.0">
- <PrivateAssets>all</PrivateAssets>
- <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
- </PackageReference>
这 3 个核心包是客户端必备的, 其中 grpc.tools 帮我们把 proto 文件转化成 C# 代码.
3. 创建 Protos 文件夹
4. 复制 Grpc.Server 项目 Protos 文件夹下的 greet.proto 文件到本项目的 Protos 文件夹
5. greet.proto 文件右键设置 gGRC Stub Classes 为 Client only.
也可以直接使用在项目文件里面代码设置如下:
- <ItemGroup>
- <Protobuf Include="Protos\greet.proto" GrpcServices="Client" />
- </ItemGroup>
6. gRPC 客户端访问服务端代码
- var channel = GrpcChannel.ForAddress("https://localhost:5001");
- var client = new Greeter.GreeterClient(channel);
- var response = client.SayHello(new HelloRequest {
- Name = "World"
- });
- Console.WriteLine(response.Message);
启动 gRPC 服务端, 在启动 gRPC 客户端控制台打印 hello Word 表示成功.
identityServer 接入 gRPC 是非常容易, 和传统 webapi 差不多.
改造 Grpc.Server 支持 IdentityServer4
1. 引入 nuget 包
<PackageReference Include="IdentityServer4.AccessTokenValidation" Version="3.0.1" />
2. startup.cs 注入服务, 和 IdentityServer4 一样.
- services.AddGrpc(x => x.EnableDetailedErrors = false);
- services.AddAuthorization();
- services.AddAuthentication(IdentityServerAuthenticationDefaults.AuthenticationScheme)
- .AddIdentityServerAuthentication(options =>
- {
- options.Authority = "http://localhost:5000";
- options.RequireHttpsMetadata = false;
- });
3. startup.cs 配置 http 请求管道
- if (env.IsDevelopment())
- {
- App.UseDeveloperExceptionPage();
- }
- App.UseRouting();
- App.UseAuthentication();
- App.UseAuthorization();
- App.UseEndpoints(endpoints =>
- {
- endpoints.MapGrpcService<GreeterService>();
- endpoints.MapGet("/", async context =>
- {
- await context.Response.WriteAsync("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");
- });
- });
4. 对需要授权的服务打标签 [Authorize], 可以打在类上也可以打在方法上
- [Authorize]
- public class GreeterService : Greeter.GreeterBase
- {
- }
这个时候我们启动 Grpc.Client 访问 Grpc.Server 服务
发现报错 401. 说明此服务需要携带令牌才能访问.
改造 Grpc.Client 携带令牌访问
- // 获取 token 可以直接使用 HttpClient 来获取, 这里使用 IdentityModel 来获取 token
- var httpClient = new HttpClient();
- var disco = await httpClient.GetDiscoveryDocumentAsync("http://localhost:5000");
- if (!disco.IsError)
- {
- var token = await httpClient.RequestClientCredentialsTokenAsync(new ClientCredentialsTokenRequest()
- {
- Address = disco.TokenEndpoint,
- ClientId = "client",
- ClientSecret = "secret"
- });
- var tokenValue = "Bearer" + token.AccessToken;
- var metadata = new Metadata
- {
- { "Authorization", tokenValue }
- };
- var callOptions = new CallOptions(metadata);
- var channel = GrpcChannel.ForAddress("https://localhost:5001");
- var client = new Greeter.GreeterClient(channel);
- var response = client.SayHello(new HelloRequest { Name = "World" }, callOptions);
- Console.WriteLine(response.Message);
- }
执行程序返回 hello world 表示成功.
传统调用 webapi 把 token 放到 Header 头的 Authorization 属性里面, grpc 是放到 Metadata 里面, 调用方法的时候传入 CallOptions. 使用上大同小异.
后记
目前 gRPC 各个语言的支持都已经很完善, 因为跨语言, 性能更高的特性非常适合做内网的通信. 笔者也将继续对 gRPC 进行跟进, 会尝试将部分的内部服务改造成 gRPC, 关于 gRPC 的相关问题也可以留言大家一起讨论.
源代码地址: https://github.com/longxianghui/grpc_ientityserver
来源: https://www.cnblogs.com/longxianghui/p/11719190.html