分享程式代碼相關筆記
目前文章總數:157 篇
最後更新:2024年 12月 07日
先連線到遠端的Server 上 -> 新建 https.conf -> 設定內容保存
建立的內容如下圖,與指令:
# 建立一個https 的連線,並且加入憑證
server {
listen 443 ssl http2;
server_name localhost;
ssl_certificate /etc/nginx/cert.crt;
ssl_certificate_key /etc/nginx/cert.key;
location / {
proxy_pass http://localhost:5099;
proxy_http_version 1.1;
proxy_set_header Host $host:$server_port;
proxy_set_header Connection "";
proxy_redirect off;
proxy_set_header X-real-ip $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
grpc_pass grpc://localhost:50051;
}
access_log /tmp/grpcHttpsChatroom.log;
error_log /tmp/grpcHttpsChatroom.error.log;
}
以下是設定說明:
listen | : | 443 - 表示走 Https 通道 |
__ | : | SSL - 表示 Https 進行 SSL/TLS 加密協議,並且表示啟用了 Https 憑證 |
__ | : | Http2 - 通信協議,比 Http/1.1 更高高效能,是在 gRPC 中預設使用的協議 |
ssl_certificate | : | 使用的公開金鑰,這個要提供給 gRPC 用戶端連線用 |
ssl_certificate_key | : | 使用的加密金鑰,為 Server 自行保管 |
proxy_pass | : | 設定網站的反代,走向內部時,會訪問我們代碼的聊天室網站, Kestreal 設定為 Http & 開啟 5099 Port |
grpc_pass | : | gRPC 傾聽的接口,走 Https 通信時, Kestreal 設定為 Https & 開啟 50051 Port |
以下兩個檔案,會在 [第二部分:建立 Https 測試憑證] 建立。
需要先建立 nginx Server的設定檔案(https.conf) 是因為憑證通常是基於域名產生
ssl_certificate | /etc/nginx/cert.crt; |
ssl_certificate_key | /etc/nginx/cert.key; |
登入 CentOs 指令列,輸入以下:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/nginx/cert.key -out /etc/nginx/cert.crt -subj "/CN=mydomain.com" -extensions SAN -config <(echo "[req]"; echo distinguished_name=req; echo "[SAN]"; echo subjectAltName=IP:192.168.51.62)
對照以上指令, {} 是要依照自己的環境設定的內容:
openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout {私鑰輸出位置} -out {公開金鑰輸出位置} -subj "/CN=mydomain.com" -extensions SAN -config <(echo "[req]"; echo distinguished_name=req; echo "[SAN]"; echo subjectAltName=IP:{本機的IP位址})
私鑰輸出位置 | : | 伺服器持有的私鑰 .key 輸出檔案位置,與 https.conf 相呼應 |
公開金鑰輸出位置 | : | 用戶端、伺服器共同持有的公鑰 .crt 輸出檔案位置,與 https.conf 相呼應 |
本機的IP位址 | : | 此 IP 為本機,在驗證憑證時會比對是否當前伺服器為合法持有者 |
我們聊天室使用的是 Kertrel Server,所以還需要將 .crt 與 .key 做 .pfx 憑證。
.pfx 憑證的特色是包含了憑證、私鑰和可能的中間憑證。簡單說 kestrel 只看打包的整合憑證。
CentOs 指令列,輸入以下:
openssl pkcs12 -export -out /etc/nginx/certificate.pfx -inkey /etc/nginx/cert.key -in /etc/nginx/cert.crt
對照以上指令, {} 是要依照自己的環境設定的內容:
openssl pkcs12 -export -out {pfx檔案輸出位置} -inkey {私鑰來源位置} -in {公開金鑰來源位置}
本篇是 Https 版本,要部署到 Server 上,需要對代碼做啟用 Https 調整
基於範例檔案改進。
需調整黃框位置的代碼:
打開 appsettings.json
加入 CertPath、PfxPath、 Kestrel 配置,部署到 Server 時,可以依照 Server 金鑰路徑調整:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"CertPath": "Certification\\cert.crt",
"PfxPath": "/etc/nginx/certificate.pfx",
"Kestrel": {
"Ports": {
"HttpPort": 5099,
"HttpsPort": 50051
}
}
}
調整 program.cs 依照1. ~ 6. 的項目依序開啟 Https 連線,並且使用 appsettings.json 的設定內容
using System.Net;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllersWithViews();
// 1. 添加gRPC
builder.Services.AddGrpc();
// 2. 取得當前gRPC Https連線配置
IConfigurationRoot baseBuilderData = new ConfigurationBuilder()
.AddJsonFile(Path.Combine(Directory.GetCurrentDirectory(), "Properties", "launchSettings.json"), optional: true, reloadOnChange: true)
.Build();
// 3. 啟用 Kestrel Server ,內部Server指向本地的https
int httpsPort = builder.Configuration.GetValue<int>("Kestrel:Ports:HttpsPort", 50051);
NetCoreGRPCChattingRoomForHttpsExample.Controllers.GlobalConst.Self_GRPC_URL = @$"https://localhost:{httpsPort}";
var certPath = builder.Configuration.GetValue<string>("CertPath", string.Empty);
NetCoreGRPCChattingRoomForHttpsExample.Controllers.GlobalConst.Cert_Path = certPath;
builder.WebHost.UseKestrel(options =>
{
// 4. 配置 Web Endpoint(HTTP/1.1) => 連網站用
var httpPort = builder.Configuration.GetValue<int>("Kestrel:Ports:HttpPort", 5099);
options.Listen(IPAddress.Any, httpPort, listenOptions => { });
// 5. 配置Https + 使用 Server 上的產生Https憑證 (此pfx 是該Server域名產生,所以Local Debug啟動會異常)
var httpsPort = builder.Configuration.GetValue<int>("Kestrel:Ports:HttpsPort", 50051);
var pfxFile = builder.Configuration.GetValue<string>("PfxPath", string.Empty);
options.Listen(IPAddress.Any, httpsPort, listenOptions =>
{
listenOptions.Protocols = Microsoft.AspNetCore.Server.Kestrel.Core.HttpProtocols.Http2;
// 5-2. 開啟Https 並且指向Server 的 HTTPS 憑證位置
listenOptions.UseHttps(pfxFile);
});
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
//6. 基本的Grpc注入使用服務
app.UseEndpoints(endpoints =>
{
endpoints.MapGrpcService<NetCoreGRPCChattingRoomForHttpsExample.Service.ChatService>();
});
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
調整 ChatController.cs 新增 static string Cert_Path 變數
public class GlobalConst
{
/// <summary>
/// 加入聊天室的用戶會記錄於此
/// </summary>
public static Dictionary<string, string> DicMessages = new Dictionary<string, string>();
public static string Self_GRPC_URL = "";
public static string Cert_Path = "";
}
調整 ChatController.cs 新建 GetGRPChannel() 方法,與調整對應的呼叫
GetGRPChannel() 方法:
/// <summary>
/// 取得公開金鑰Cert
/// </summary>
/// <returns></returns>
private static GrpcChannel? GetGRPChannel()
{
var rootCert = System.IO.File.ReadAllText(NetCoreGRPCChattingRoomForHttpsExample.Controllers.GlobalConst.Cert_Path);
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(new X509Certificate2(Encoding.UTF8.GetBytes(rootCert)));
//如果憑證為測試憑證必須加入這行,如果生產有產生正式的Https 憑證把此行註解即可
handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
var channelOptions = new GrpcChannelOptions
{
HttpClient = new HttpClient(handler)
};
var client = GrpcChannel.ForAddress(GlobalConst.Self_GRPC_URL, channelOptions);
return client;
}
調整對應的呼叫:
// 1. 調整加入Https cert公開金鑰
using (var channel = GetGRPChannel())
{
...
業務邏輯略
...
}
專案 -> 右鍵 -> 發布程式
將檔案內容部署到 CentOs Server 上
依照自己環境,調整 .crt 與 .pfx 的檔案路徑
輸入以下指令啟動 dotnet core 的 kestrel Server
dotnet NetCoreGRPCChattingRoomForHttpsExample.dll
聊天室已經可以使用 Https 做訂閱、推送
注意到為不安全,是因為憑證是用測試憑證,如果是生產環境,對外網域的情況下,這邊就不會跳出 Https 不安全的提示訊息
這邊提供獨立的客戶端建立 Https 憑證的方式,可以參考 HttpsGrpcConnetionTest 專案
今天若為 Android、IOS、JavaScript 情況下也可以參考做調整
代碼完整內容如下:
1 - 4 | : | 基本配置步驟 |
5, 6-1, 6-2 | : | 設定憑證,與指定方法 |
7, 8 | : | 客戶端要知道伺服器端的連線位置,並建立連線 |
9 | : | 呼叫 gRPC 的 SendMessageAsync() , 發送訊息測試 |
10 | : | 訂閱資料,永遠保持連線,當伺服器端推播資料時,永遠都會收到資訊 |
using ChatApp;
using Grpc.Core;
using Grpc.Net.Client;
using System.Security.Cryptography.X509Certificates;
using System.Text;
//1. 將正確的 proto 複製到 Protos 資料夾下
//2. 加入服務參考 -> 用戶端 -> 最新的.proto 檔案
//3. 從Server 環境下取得憑證檔案 EX: /etc/nginx/cert.crt
//4. 指向檔案路徑 (※這個是測試憑證,基本上沒什麼用處)
var rootCert = File.ReadAllText(@"Certification\cert.crt");
//5. 設定憑證
var handler = new HttpClientHandler();
handler.ClientCertificates.Add(new X509Certificate2(Encoding.UTF8.GetBytes(rootCert)));
//6-1. 測試環境可以開啟這個,因為憑證是我們產的測試Https 憑證,但生產需要將此行註解
handler.ServerCertificateCustomValidationCallback = HttpClientHandler.DangerousAcceptAnyServerCertificateValidator;
//6-2. 建立HttpClient
var channelOptions = new GrpcChannelOptions
{
HttpClient = new HttpClient(handler)
};
//7. 指定連線gRPC目標
using var channel = GrpcChannel.ForAddress("https://192.168.51.62:50051", channelOptions);
//8. 建立聯繫
var client = new ChatApp.ChatService.ChatServiceClient(channel);
//9. 發送一個訊息
var sendResponseStream = client.SendMessageAsync(new MessageRequest() { Message = "Hello", Username = "Louis" });
//10. 開啟訂閱模式,等待資料推播過來
using (var subScribeResponseStream = client.Subscribe())
{
using (var subscribeCall = client.Subscribe())
{
var subscribeRequest = new SubscribeRequest { SubscriberName = "Https Subscriber From Client" };
await subscribeCall.RequestStream.WriteAsync(subscribeRequest);
// 接收消息
var receiveTask = Task.Run(async () =>
{
await foreach (var message in subscribeCall.ResponseStream.ReadAllAsync())
{
Console.WriteLine($"Received message: {message.Content}");
}
});
// 等待接收消息的任務完成
await receiveTask;
}
}
我們啟動客戶端程式後,會發送一個訊息,接著加入訂閱模式
並且從 Https Server 聊天室發送訊息時,該客戶端也會同步收到訊息,完成 Https 下的聊天室功能