.Net Core 3.1 配置的grpc服务项目 采用证书绑定
var config = new ConfigurationBuilder().AddJsonFile("appsettings.json", optional: true, reloadOnChange: true).Build();
var certificateSettings = config.GetSection("certificateSettings").Get<Model.certificateSettings>();
string certificateFileName = certificateSettings.fileName;
string certificatePassword = certificateSettings.password;
var certificate = new X509Certificate2(Path.Combine(AppContext.BaseDirectory,certificateFileName), certificatePassword);
var httpsConnectionAdapterOptions = new HttpsConnectionAdapterOptions()
{
ClientCertificateMode = ClientCertificateMode.AllowCertificate,
SslProtocols = System.Security.Authentication.SslProtocols.Tls12,
//用chain.Build验证客户端证书
ClientCertificateValidation = (cer, chain, error) =>
{
return chain.Build(cer);
},
ServerCertificate = certificate
};
webBuilder.UseKestrel(serverOptions =>
{
serverOptions.Limits.MaxRequestBodySize = null;
serverOptions.AllowSynchronousIO = true;
serverOptions.Limits.KeepAliveTimeout = TimeSpan.FromMinutes(2);
//在使用阿里云和其他云服务商的服务器时需要注意配置安全组策略
//需要把使用到的端口配置到安全组中并开放
//否则在访问过程中会导致端口无法访问的情况
//使用https的端口需要注意的问题就是需要配置证书和证书的秘钥
//注意证书路径
serverOptions.ListenAnyIP(443, (option) =>
{
option.UseHttps(httpsConnectionAdapterOptions);
});
}).UseStartup<Startup>();
在客户端使用的时候调用
```c#
try
{
var handler = new HttpClientHandler();
handler.ClientCertificateOptions = ClientCertificateOption.Manual;
handler.SslProtocols = SslProtocols.Tls12;
//获取证书路径
//商户私钥证书,用于对请求报文进行签名
try
{
// var path = AppDomain.CurrentDomain.BaseDirectory + "cert\\xxx.pfx";
//var crt = new X509Certificate2(path, "xxx");
handler.ClientCertificates.Add(new X509Certificate2(AppDomain.CurrentDomain.BaseDirectory + "cert\\xxx.pfx", "xxx", X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet));
}
catch (Exception e)
{
}
handler.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls11 | SslProtocols.Tls;
handler.ServerCertificateCustomValidationCallback = (message, cert, chain, errors) => true;
var channel = Grpc.Net.Client.GrpcChannel.ForAddress("https://xxx.cn", new GrpcChannelOptions { HttpHandler = handler });
var client = new Calculator.CalculatorClient(channel);
var greeter = new Greeter.GreeterClient(channel);
var reply = await greeter.SayHelloAsync(new HelloRequest { Name = ".NET" });
}
catch (Exception ex)
{
throw new Exception(ex.Message);
}
会出现如下错误 (http可以正常访问 https就会出现这个错误 我用浏览器访问域名证书是正常的 )
Status(StatusCode="Unavailable", Detail="Error starting gRPC call. HttpRequestException: An error occurred while sending the request. IOException: The response ended prematurely.", DebugException="System.Net.Http.HttpRequestException: An error occurred while sending the request.
---> System.IO.IOException: The response ended prematurely.
at System.Net.Http.HttpConnection.FillAsync()
at System.Net.Http.HttpConnection.ReadNextResponseHeaderLineAsync(Boolean foldedHeadersAllowed)
at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.HttpConnection.SendAsyncCore(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithNtConnectionAuthAsync(HttpConnection connection, HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at Grpc.Net.Client.Internal.GrpcCall`2.RunCall(HttpRequestMessage request, Nullable`1 timeout)")