.Net Core3.0使用gRPC 和IdentityServer4

gRPC是什麼
gRPC是能夠在任何環境中運行的現代開源高性能RPC框架。它能夠經過可插拔的支持來有效地鏈接數據中心內和跨數據中心的服務,以實現負載平衡,跟蹤,運行情況檢查和身份驗證。它也適用於分佈式計算的最後一英里,以將設備,移動應用程序和瀏覽器鏈接到後端服務。html

proto文件
用於定義gRPC服務和消息的協定;服務端和客戶端共享proto文件。web

使用新模板建立gRPC服務端
.NETcore 3.0建立項目提供了一個新的gRPC模板,能夠輕鬆地使用ASP.NET Core構建gRPC服務。咱們按照步驟一步一步建立AA.GrpcService 服務,固然你可使用命令:dotnet new grpc -o GrpcGreeter後端

 選擇gRPC服務項目模板api

 

最終生成的項目瀏覽器

 

syntax = "proto3";
 
option csharp_namespace = "AA.GrpcService";
 
package Greet;
 
// The greeting service definition.
service Greeter {
  // Sends a greeting
  rpc SayHello (HelloRequest) returns (HelloReply);
}
 
// The request message containing the user's name.
message HelloRequest {
  string name = 1;
}
 
// The response message containing the greetings.
message HelloReply {
  string message = 1;
}

GreeterService.cs網絡

 public class GreeterService : Greeter.GreeterBase
    {
        private readonly ILogger<GreeterService> _logger;
        public GreeterService(ILogger<GreeterService> logger)
        {
            _logger = logger;
        }
 
        public override Task<HelloReply> SayHello(HelloRequest request, ServerCallContext context)
        {
            return Task.FromResult(new HelloReply
            {
                Message = "Hello " + request.Name
            });
        }
    }


Startup.csapp

public class Startup
    {
        // This method gets called by the runtime. Use this method to add services to the container.
        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddGrpc();
        }
        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            app.UseRouting();
            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");
                });
            });
        }
    }


建立完成以後,自動包含了包的引用、proto文件的建立、services服務的生成,模板項目在後臺執行一些操做如框架

建立一個包含全部gRPC依賴項的ASP.NET Core項目。
建立一個名爲的gRPC服務定義文件greet.proto。
根據服務定義文件自動生成全部gRPC存根。
GreeterService.cs根據自動生成的gRPC存根建立gRPC服務。
在Startup.cs中配置gRPC管道映射到GreeterService.cs
運行服務async

 

建立gRPC客戶端
下面,咱們建立一個控制檯應用程序做爲客戶端調用gRPC服務;分佈式

 

引用gRPC服務,步驟:右鍵項目添加=》服務引用彈出如下頁面;

 

點擊肯定

 

 

 

咱們看項目結構,他們會自動幫咱們處理一下操做:

添加引用包:
 package Grpc.Net.ClientFactory
 package Google.Protobuf
 package Grpc.Tools
Protos 文件(包含greet.proto)自動從AA.GrpcService項目拷貝
自動添加節點

<ItemGroup>
  <Protobuf Include="..\AA.GrpcService\Protos\greet.proto" GrpcServices="Client">
    <Link>Protos\greet.proto</Link>
  </Protobuf>
</ItemGroup>

最後,添加如下代碼進行gRPC請求;

  static async System.Threading.Tasks.Task Main(string[] args)
        {
            var httpClientHandler = new HttpClientHandler();
            httpClientHandler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
            var httpClient = new HttpClient(httpClientHandler);
 
            using var channel = GrpcChannel.ForAddress("https://localhost:5002", new GrpcChannelOptions { HttpClient = httpClient });
            var client = new Greeter.GreeterClient(channel);
            var response = await client.SayHelloAsync(new HelloRequest { Name = "gRPC" });
            Console.WriteLine("Greeting:" + response.Message);
            Console.WriteLine("Press a key to exit");
            Console.ReadKey();
        }

運行結果圖:

 

gRPC與IdentityServer4集成認證受權
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=client&client_secret=secret

{
"access_token":"eyJhbGciOiJSUzI1NiIsImtpZCI6IlVYODJRTk9LMWRMR1dDREVUd0xQbkEiLCJ0eXAiOiJhdCtqd3QifQ.eyJuYmYiOjE1NzE4MDU4MzAsImV4cCI6MTU3MTgwOTQzMCwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MDAwIiwiYXVkIjoiYXBpIiwiY2xpZW50X2lkIjoiY2xpZW50Iiwic2NvcGUiOlsiYXBpIl19.DgJJqIOOSICEGa7S5R4Ok7Pp4hxPjGQP12T4LsDHD5tRsYiV58VcvooglVehKmMbydE7yA7JnYqBR--2Gbss9zjYyq41iY2lP-Y79v70jlVn9TvrpWOIljnWOvLApjFMEXJuV4VHwcXQ7ssgXFrY4Mg_QPaxkJRIKAI8T5cP2W1KvOBkaZqx45o8VpQBfpEyoRjPHQW0wPrM6bBU4IxfTosy874pn2NXVhe2DaPeAcReXYsz5AVtJ4Vt-4fVS1JtcA-aj6OQ__RWYqNK_ApQRFZsuyJKG27EBBrc0byrpw_G1PReRl8hlYnXidGFvijGEawlyEAANXzNNXDk7cSJ2A",
"expires_in":3600,
"token_type":"Bearer",
"scope":"api"
}

改造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攜帶令牌訪問(須要添加IdentityServer4引用)

 static async System.Threading.Tasks.Task Main(string[] args)
        {
            var httpClientHandler = new HttpClientHandler();
            httpClientHandler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
            var httpClient = new HttpClient(httpClientHandler);
 
            //獲取token能夠直接使用HttpClient來獲取,這裏使用IdentityModel來獲取token
            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);
                ////
                using var channel = GrpcChannel.ForAddress("https://localhost:5002", new GrpcChannelOptions { HttpClient = httpClient });
                var client = new Greeter.GreeterClient(channel);
                var response = await client.SayHelloAsync(new HelloRequest { Name = "gRPC" },callOptions);
                Console.WriteLine("Greeting:" + response.Message);
            }
             
            Console.WriteLine("Press a key to exit");
            Console.ReadKey();
        }

小結: .NETcore 3.0 使得使用gRPC是很是方便集成到項目中,但願這篇文章使你能夠了解.NETcore與gRPC結合使用。那gRPC適用於如下場景

微服務– gRPC專爲低延遲和高吞吐量通訊而設計。 gRPC對於效率相當重要的輕量級微服務很是有用。

點對點實時通訊– gRPC對雙向流具備出色的支持。 gRPC服務能夠實時推送消息而無需輪詢。

多種語言環境– gRPC工具支持全部流行的開發語言,所以gRPC是多語言環境的理想選擇。

網絡受限的環境– gRPC消息使用輕量級消息格式Protobuf進行了序列化。 gRPC消息始終小於等效的JSON消息。

參考:

https://docs.microsoft.com/en-us/aspnet/core/grpc/troubleshoot?view=aspnetcore-3.0

https://docs.microsoft.com/zh-cn/aspnet/core/grpc/?view=aspnetcore-3.0https://www.grpc.io/https://developers.google.com/protocol-buffers/docs/proto3https://www.cnblogs.com/stulzq/p/11581967.html

相關文章
相關標籤/搜索