.net core https 双向验证
文章来自:https://www.cnblogs.com/axzxs2001/p/10070562.html
关于https双向认证的知识可先行google,这时矸接代码。
为了双向认证,我们首先得准备两个crt证书,一个是client.crt,一个是server.crt,有时为了验证是否同一个根证书的验证,这两个证书可以共有一个根证书root.crt。
首先要生成这些证书,这里采用了自签证书方式:
证书生成工具可在这里下载(windows下生成):
安装完成后在C:\OpenSSL-Win64\bin(最好不要改路径,否则生成证书时要改配置文件路径)下以管理员运行openssl.exe
一、创建根证书
- 生成key文件,输入密码:
openssl genrsa -des3 -out root.key
- 生成请求证书文件,如果安装路径发生改变,可以通过在下面命令后面添加-config openssl.cfg来指明配置文件路径
openssl req -new -key root.key -out root.csr
- 生成一个10年期根证书 root.crt:
openssl x509 -req -days 3650 -sha1 -extensions v3_ca -signkey root.key -in root.csr -out root.crt
分别在客户端或服务端安装根证书,windows上安装证书时,证书存储可选择“受信任的根证书颁发机构”
二、创建服务端证书
- 生成key文件,输入密码
openssl genrsa -des3 -out server.key 2048
- 生成请求证书文件,如果安装路径发生改变
openssl req -new -key server.key -out server.csr
- 用根证书生成一个10年期证书 server.crt:
openssl x509 -req -days 3650 -sha1 -extensions v3_req -CA root.crt -CAkey root.key -CAserial root.srl -CAcreateserial -in server.csr -out server.crt
- 生成.net core识别的证书文件server.pfx
openssl pkcs12 -export -in server.crt -inkey server.key -out server.pfx
三、创建客户端证书
- 生成key文件,输入密码
openssl genrsa -des3 -out client.key 2048
- 生成请求证书文件,如果安装路径发生改变
openssl req -new -key client.key -out client.csr
- 用根证书生成一个10年期证书 client.crt:
openssl x509 -req -days 3650 -sha1 -extensions v3_req -CA root.crt -CAkey root.key -CAserial root.srl -CAcreateserial -in client.csr -out client.crt
- 生成.net core识别的证书文件client.pfx
openssl pkcs12 -export -in client.crt -inkey client.key -out client.pfx
接下来创建asp.net core web api项目,并把server.pfx添加到项目中,并设置属性为“始终复制”,接着修改Program.cs下的CreateWebHostBuilder方法就可以:
builder.WebHost.ConfigureKestrel(options => { options.Listen(IPAddress.Any, builder.Configuration.GetSection("Port").Get<int>(), listenOptions => { var serverCertificate = new X509Certificate2(“./yourcertfile.pfx”, "123456"); var httpsConnectionAdapterOptions = new HttpsConnectionAdapterOptions() { ClientCertificateMode = ClientCertificateMode.RequireCertificate, SslProtocols = SslProtocols.None, ClientCertificateValidation = (cer, chain, error) => { if ( !string.IsNullOrEmpty( Global.AppConfig.Current.ClientCertHash ) && cer.GetCertHashString() != Global.AppConfig.Current.ClientCertHash) return false; return true; }, ServerCertificate = serverCertificate }; listenOptions.UseHttps(httpsConnectionAdapterOptions); }); });
为了区分http和https请求,在HomeController中写如下代码:
1 [HttpGet] 2 public ActionResult<IEnumerable<string>> Get() 3 { 4 var cer = HttpContext.Connection.ClientCertificate; 5 //证书为空,返回BadRequest 6 if (cer == null) 7 { 8 return BadRequest(); 9 } 10 else 11 { 12 return new string[] { "value1", "value2" }; 13 } 14 }
创建客户应用,.net core的控制台项目,把client.pfx添加到项目中,并设置属性为“始终复制”,然后代码如下
1 static void Main(string[] args) 2 { 3 Console.WriteLine("enter start"); 4 while (true) 5 { 6 try 7 { 8 Console.WriteLine("1、Https 2、Http"); 9 switch (Console.ReadLine()) 10 { 11 case "1": 12 HttpsMethod(); 13 break; 14 case "2": 15 HttpMethod(); 16 break; 17 } 18 void HttpsMethod() 19 { 20 var handler = new HttpClientHandler(); 21 handler.ClientCertificateOptions = ClientCertificateOption.Manual; 22 handler.SslProtocols = SslProtocols.Tls12 | SslProtocols.Tls | SslProtocols.None | SslProtocols.Tls11; 23 try 24 { 25 //加载客户端证书 26 var crt = new X509Certificate2(Directory.GetCurrentDirectory() + "/client.pfx", "cccccc"); 27 handler.ClientCertificates.Add(crt); 28 } 29 catch (Exception e) 30 { 31 Console.WriteLine(e.Message); 32 } 33 //用chain.Build验证服务器证书 34 handler.ServerCertificateCustomValidationCallback = (message, cer, chain, errors) => 35 { 36 return chain.Build(cer); 37 }; 38 var client = new HttpClient(handler); 39 var url = "https://192.168.252.41 /api/values"; 40 var response = client.GetAsync(url).Result; 41 Console.WriteLine(response.IsSuccessStatusCode); 42 var back = response.Content.ReadAsStringAsync().Result; 43 Console.WriteLine(back); 44 } 45 void HttpMethod() 46 { 47 var client = new HttpClient(); 48 var url = "http://192.168.252.41/api/values"; 49 var response = client.GetAsync(url).Result; 50 Console.WriteLine(response.IsSuccessStatusCode); 51 var back = response.Content.ReadAsStringAsync().Result; 52 Console.WriteLine(back); 53 } 54 } 55 catch (Exception exc) 56 { 57 Console.WriteLine(exc.InnerException?.InnerException?.Message); 58 } 59 } 60 }