.NET Framework客户端使用WinHttpHandler结合X509Certificate调用.NET 5.0 gRPC HTTP2服务时遇路径非法字符异常
搞定.NET Framework gRPC客户端加载证书时的"Illegal characters in path"异常
嘿,我一眼就看出你遇到的问题根源了——证书加载方法用错参数了!
为什么会报错?
你调用X509Certificate.CreateFromSignedFile(clientCert)的时候,传的是File.ReadAllText(@"client.crt")读出来的证书内容字符串,但这个方法的参数要求的是证书文件的路径啊!证书内容里满是-----BEGIN CERTIFICATE-----、换行符这种非法路径字符,方法直接懵了,自然就抛出"Illegal characters in path"异常了。
正确的打开方式
针对.NET Framework做gRPC双向认证,推荐用X509Certificate2(它支持加载带私钥的证书,这是双向认证必须的),给你两种方案:
方案1:用PFX格式证书(最省心)
先把你的客户端证书和私钥合并成PFX文件(带密码),然后直接加载:
// 加载带私钥的PFX证书 let clientCert = new X509Certificate2(@"client.pfx", "你的证书密码") let handler = new WinHttpHandler() handler.ClientCertificates.Add(clientCert) |> ignore // 临时跳过服务端证书验证,生产环境别这么干! handler.ServerCertificateValidationCallback <- fun msg clientcert cacert e -> true let httpclient = new HttpClient(handler) let channelOptions = GrpcChannelOptions(HttpClient = httpclient) let channel = GrpcChannel.ForAddress("https://127.0.0.1:5001", channelOptions) let client = DeFactoGrpc.EventSubscriberService.EventSubscriberServiceClient(channel)
方案2:从分开的crt和key文件加载(需要BouncyCastle)
如果不想转PFX,就得用第三方库BouncyCastle来合并证书和私钥:
open Org.BouncyCastle.Crypto open Org.BouncyCastle.Crypto.Parameters open Org.BouncyCastle.OpenSsl open Org.BouncyCastle.X509 open System.IO open System.Security.Cryptography.X509Certificates // 加载证书文件 let certBytes = File.ReadAllBytes(@"client.crt") let cert = new X509CertificateParser().ReadCertificate(certBytes) // 加载私钥文件 let keyReader = new StreamReader(@"client.key") let keyParser = new PemReader(keyReader) let privateKey = keyParser.ReadObject() :?> AsymmetricCipherKeyPair // 用BouncyCastle打包成PFX格式 let pkcs12Store = new Org.BouncyCastle.Pkcs.Pkcs12Store() let certEntry = new Org.BouncyCastle.Pkcs.X509CertificateEntry(cert) pkcs12Store.SetCertificateEntry("clientCert", certEntry) pkcs12Store.SetKeyEntry("clientKey", new Org.BouncyCastle.Pkcs.AsymmetricKeyEntry(privateKey.Private), [| certEntry |]) let ms = new MemoryStream() pkcs12Store.Save(ms, "临时密码".ToCharArray(), new SecureRandom()) ms.Position <- 0 // 转成X509Certificate2 let clientCert = new X509Certificate2(ms.ToArray(), "临时密码") // 后续和方案1一样配置WinHttpHandler和gRPC通道 let handler = new WinHttpHandler() handler.ClientCertificates.Add(clientCert) |> ignore // ... 剩下的代码就不用改啦
小提醒
- 双向认证必须要客户端证书带私钥,否则服务端会直接拒接,所以PFX是最省事的选择。
- 你的服务端代码没问题,
SslServerCredentials本来就是接受证书内容字符串的,不用改。
内容的提问来源于stack exchange,提问作者tobiasholmdk
相关产品推荐
相关产品推荐

