无法连接到本链接中提到的greeter grpc服务-https://docs . Microsoft . com/en-us/aspnet/core/tutorials/grpc/grpc-start?欢迎客户端的view=aspnetcore-3.0,它是使用grpc.core库(< code>Grpc)从. net framework应用程序编写的。核心2.24.0和< code>Grpc。Core.Api.2.24.0)。
下面是我的客户端代码。它适用于非SSL,但不适用于SSL
使用非SSL的客户端代码(这是可行的)
var channel = new Channel("localhost:5000", ChannelCredentials.Insecure);
var client = new Greeter.GreeterClient(channel);
var reply = await client.SayHelloAsync(new HelloRequest { Name = "GreeterClient" });
channel.ShutdownAsync().Wait();
使用SSL的客户端代码(此连接失败)
SslCredentials secureChannel = new SslCredentials();
var channel = new Channel("localhost", 5001, secureChannel);
var client = new Greeter.GreeterClient(channel);
var reply = await client.SayHelloAsync(new HelloRequest { Name = "GreeterClient" });
channel.ShutdownAsync().Wait();
我使用SSL得到的错误是:
Grpc.Core.RpcException:'状态(StatusCode=不可用, Detail="无法连接到所有地址")'
我尝试了同一链接中提到的.net核心应用程序客户端(https://docs.microsoft.com/en-us/aspnet/core/tutorials/grpc/grpc-start?view=aspnetcore-3.0),它与SSL和非SSL一起工作,但不直接使用grp库。我的客户端是.Net framework客户端,这就是我无法使用.Net库连接到grpc服务的原因。Net核心应用程序仅支持.Net grpc库。
SslCredentials secureChannel = new SslCredentials();
var channel = new Channel("localhost", 5001, secureChannel);
var client = new Greeter.GreeterClient(channel);
var reply = await client.SayHelloAsync(new HelloRequest { Name = "GreeterClient" });
channel.ShutdownAsync().Wait();
预期结果-来自服务器的响应
实际结果-<code>Grpc.Core。RPCEException:“状态(状态代码=不可用,详细信息=无法连接到所有地址”)
我在不保存客户端的pem的情况下使其工作(如果客户端和服务器在不同的机器上,则发生事件)。
首先,非常重要的是,目标/主机名(用于创建通道的名称)必须与服务器证书中的CN(通用名称)相匹配,这里需要注意的是它区分大小写!
e.q: 证书的 CN 是 SV-XXX-DEV-01,您指定 sv-xxx-dev-01 这将不起作用,并且您会收到以下错误:
Grpc.Core.RpcException: 'Status(StatusCode=Unavailable, Detail="failed to connect to all addresses")'
所以下面是我的解决方案(当然这个可以优化,不应该在一个类里(关注点分离),但是更容易抓住重点。
public static async Task Main(string[] args)
{
await FullFrameworkSample();
}
private static async Task FullFrameworkSample()
{
Uri host = new Uri("https://sv-xxx-dev-cpu-01:44301");
int port = host.Port;
(string publicKeyInPemFormat, string commonName) = await GetCertificateInformationFromServer(host);
//note: in the full framework implementation it's very important that the casing of the target is correct (the same casing as in the CN name of the certificate)
string target = $"{commonName}:{port}";
//note: thats only needed in our case, because we have a server side interceptor, that checks if the secureKey is valid.
CallCredentials credentials = CallCredentials.FromInterceptor((context, metadata) =>
{
metadata.Add("SecurityTokenId", "someSecureKey");
return Task.CompletedTask;
});
ChannelCredentials channelCredentials = ChannelCredentials.Create(new SslCredentials(publicKeyInPemFormat), credentials);
Channel channel = new Channel(target, channelCredentials);
ProjectInlayDataService.ProjectInlayDataServiceClient client = new ProjectInlayDataService.ProjectInlayDataServiceClient(channel);
GetProjectInlayDataResponse result = await client.GetProjectInlayDataAsync(new GetProjectInlayDataRequest());
await channel.ShutdownAsync();
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
private static async Task<(string PublicKeyInPemFormat, string CommonName)> GetCertificateInformationFromServer(Uri host)
{
Regex commonNameRegex = new Regex("CN=([\\w\\-.]*),?", RegexOptions.Compiled | RegexOptions.IgnoreCase);
StringBuilder builder = new StringBuilder();
const string newline = "\n";
X509Certificate certFromServer;
using (HttpClient client = new HttpClient())
{
using (HttpResponseMessage _ = await client.GetAsync(host))
{
//get the certificate from the server, so we don't need to store the pem.
certFromServer = ServicePointManager.FindServicePoint(host).Certificate;
if (certFromServer == null)
throw new InvalidOperationException($"Could not get certificate from server ({host}).");
}
}
Match match = commonNameRegex.Match(certFromServer.Subject);
if (!match.Success)
throw new InvalidOperationException($"Could not extract CN (Common Name) from server certificate ({certFromServer.Subject}).");
string commonName = match.Groups[1].Captures[0].Value;
X509Certificate2 certificate = new X509Certificate2(certFromServer);
string pem = ExportToPem(certificate);
builder.AppendLine(
"# Issuer: " + certificate.Issuer + newline +
"# Subject: " + certificate.Subject + newline +
"# Label: " + certificate.FriendlyName + newline +
"# Serial: " + certificate.SerialNumber + newline +
"# SHA1 Fingerprint: " + certificate.GetCertHashString() + newline +
pem + newline);
return (builder.ToString(), commonName);
}
/// <summary>
/// Export a certificate to a PEM format string
/// </summary>
/// <param name="cert">The certificate to export</param>
/// <returns>A PEM encoded string</returns>
private static string ExportToPem(X509Certificate cert)
{
StringBuilder builder = new StringBuilder();
builder.AppendLine("-----BEGIN CERTIFICATE-----");
builder.AppendLine(Convert.ToBase64String(cert.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks));
builder.AppendLine("-----END CERTIFICATE-----");
return builder.ToString();
}
}
我通过在客户端使用服务器的pem格式的证书来使用SSL端口。
SslCredentials secureCredentials = new SslCredentials(File.ReadAllText("certificate.pem"));
var channel = new Channel("localhost", 5001, secureCredentials);
稍作说明,VS 2019中的Asp.NETCore模板使用带有pfx文件的开发证书,位于%AppData%\ASP.NET\Https\ProjectName.pfx
和密码=%AppData%\Microsoft\UserSecrets\{UserSecresId}\secrets.json{: Kestrel:证书:开发:密码}值
您可以从ProjectName.csproj
获取UserSecresId
id。这对于每个ASP.NET核心项目都不同。
我们只需要一个< code>certificate.pem文件形式的证书公钥,就可以通过gRPC进行安全通信。使用下面的命令从pfx提取publickey
openssl pkcs12 -in "<DiskLocationOfPfx>\ProjectName.pfx" -nokeys -out "<TargetLocation>\certifcate.pem"
复制此证书。供gRPC.NET Framework客户端使用的pem。
SslCredentials secureCredentials = new SslCredentials(File.ReadAllText("<DiskLocationTo the Folder>/certificate.pem"))
var channel = new Channel("localhost", 5001, secureCredentials);
请注意,我使用的端口 5001 是我 ASP.NET 核心应用程序的 SSL 端口。
对于生产场景
使用来自证书签名颁发机构的有效证书,并在 ASP.NET 核心服务器和 .NET Framework 客户端中分别使用与 pfx 和 pem 相同的证书。
或使用自签名证书
对于在我们自己的微服务之间通信的大多数微服务来说,使用自签名证书是一种有效的选择。我们可能不需要权威机构签署的证书。使用自签名证书可能会遇到的一个问题是,证书可能会颁发给某个目标DNS名称,我们的gRPC服务器可能正在其他地方运行,无法建立安全连接。
使用gRPC目标名称覆盖密钥覆盖ssl目标名称验证。
List<ChannelOption> channelOptions = new List<ChannelOption>()
{
new ChannelOption("grpc.ssl_target_name_override", <DNS to which our certificate is issued to>),
};
SslCredentials secureCredentials = new SslCredentials(File.ReadAllText("certificate.pem"));
var channel = new Channel("localhost", 5001, secureCredentials, channelOptions);
我做了一个工作客户。在. NET Framework c上运行服务器。本地主机上的NET Core:
static async Task Main(string[] args)
{
string s = GetRootCertificates();
var channel_creds = new SslCredentials(s);
var channel = new Channel("localhost",50051, channel_creds);
var client = new Informer.InformerClient(channel);
await GetPing(client);
}
public static string GetRootCertificates()
{
StringBuilder builder = new StringBuilder();
X509Store store = new X509Store(StoreName.Root);
store.Open(OpenFlags.ReadOnly);
foreach (X509Certificate2 mCert in store.Certificates)
{
builder.AppendLine(
"# Issuer: " + mCert.Issuer.ToString() + "\n" +
"# Subject: " + mCert.Subject.ToString() + "\n" +
"# Label: " + mCert.FriendlyName.ToString() + "\n" +
"# Serial: " + mCert.SerialNumber.ToString() + "\n" +
"# SHA1 Fingerprint: " + mCert.GetCertHashString().ToString() + "\n" +
ExportToPEM(mCert) + "\n");
}
return builder.ToString();
}
/// <summary>
/// Export a certificate to a PEM format string
/// </summary>
/// <param name="cert">The certificate to export</param>
/// <returns>A PEM encoded string</returns>
public static string ExportToPEM(X509Certificate cert)
{
StringBuilder builder = new StringBuilder();
builder.AppendLine("-----BEGIN CERTIFICATE-----");
builder.AppendLine(Convert.ToBase64String(cert.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks));
builder.AppendLine("-----END CERTIFICATE-----");
return builder.ToString();
}
private static async Task GetPing(Informer.InformerClient client)
{
Console.WriteLine("Getting ping...");
try
{
Metadata headers = null;
var response = await client.GetServerPingAsync(new Empty(), headers);
string result = "Nan";
if (response.PingResponse_ == 1)
result = "Ok!";
Console.WriteLine($"Ping say: {result }");
}
catch (Exception ex)
{
Console.WriteLine("Error get server ping." + Environment.NewLine + ex.ToString());
}
}
但是我还没有成功地在远程计算机上完成这项工作(例如,其中ip 192.168.1.7是服务器地址,客户端地址是192.168.1.2)。
我无法连接到我的节点。js服务器。当通过节点使用http web服务器在本地运行它时,它工作得很好,但是当连接到外部时,它会加载<code>socket.io。js文件很好,但当尝试使用套接字时,它会从URL中删除端口,无法连接。 而不是在网络请求中执行此操作: http://external-domain.com:3000/socket.io/?EIO=3 它是这样做的: http://exte
我已经看了很长一段时间了,在互联网上浏览了所有不同的帖子,看看是否能找到有相同问题的人,但不知为什么,我似乎是唯一有这个问题的人。 我有一个ASP。net核心服务器,运行Grpc的基本迎宾服务。使用程序“BloomRPG”调用此服务器效果很好,而且响应时间也很长。然而,当我试图从自己编写的(非常基本的)客户机上执行同样的操作时,我会遇到以下错误: 在客户机上: dbug:Grpc。网客户内部的Gr
问题内容: 我完全被困在这里。我有一个Java客户端代码,需要使用自签名证书连接到SSL服务器。 仅 当我在服务器端禁用SSLv2支持时, 才会 出现此问题。 痕迹是 在服务器端,我可以看到以下跟踪: 如果启用SSL2,我会看到 而且一切正常。 我还知道那不是服务器端的东西,因为与其他软件连接可以正常工作。 知道我在做什么错吗? 还有人知道这个“读取客户端问候A / B”是什么意思吗? 谢谢 更新
将grpc定义的服务视为: 并利用客户端连接到此服务类似于: 如果我们要在一个单独的线程中生成调用,那么处理终止一个永远运行、我们不想再使用的grpc连接的正确方法是什么?是否有任何连接或流控制方法可以调用?
我正在尝试在GKE上部署gRPC,我遵循了本教程-https://cloud.google.com/solutions/exposing-grpc-services-on-gke-using-envoy-proxy 我完成了所有工作,但我似乎无法在golang上运行gRPC,而我可以在grpcurl上运行它。 有人有什么想法吗?
所有的 我正在尝试连接到Oracle 19C数据库。我安装了两个Oracle客户端(11g和12c),因为我们需要支持遗留程序。我可以通过12c客户端与使用sqlplus的任何用户连接,没有问题。但是如果我与任何用户一起使用11g(11.2.0)客户端。我总是得到: 两个客户端都有完全相同的sqlnet。ora和tnsnames。ora文件,因此两个客户端都指向同一个数据库。 有什么想法吗?我是否