http內網穿透CYarp[開源]

0 前言

在物聯網領域中,mqtt消息一直是海量設備連接到平臺的標配協議,而平臺向移動端開放的操作接口往往是http協議,這就要求平臺爲兩種協議作消息一一適配。在某些情況下,這些設備是有操作系統的linux或安卓設備,如果我們換個思路,讓這些設備直接提供http協議的操作接口(httpd服務器),平臺端使用隧道打通設備與移動端的傳輸層,做爲平臺開發人員,就可以省去時間做這些繁瑣的消息級別的一一適配工作了。

1 面臨的問題

1.1 海量連接

mqtt默認基於tcp傳輸,一臺設備與平臺維持一個tcp連接即可高效的上下並行傳輸消息。而http/1.1在協議層限制了單個連接串行請求響應,但我們可以使用http/2.0或http/3.0做爲http/1.1的傳輸層,也能達到一個物理鏈接多路傳輸http/1.1的目的。這樣下來內網http/1.1穿透也和mqtt一樣,只需要一個物理長連接。

1.2 身份認證

我嘗試使用frp來承載物聯網設備的http內網穿透,但至今還沒成功完成海量設備的一機一密的身份認證,它裏面的token認證方式只適合一平臺對一個設備的安全要求,而OIDC驗證我至今仍然看不明白怎麼使用。對於一款內網穿透組件或應用,能像asp.netcore的身份驗證強大,對平臺端而言是非常需要的。

1.3 安全傳輸

設備內置的http服務器,一般都是沒有https,因爲它本身就不考慮公網傳輸的能力。但在內網穿透之後,我們必須要考慮設備到公網平臺這段的傳輸安全。

1.4 開放協議

內網穿透組件涉及到平臺的服務端和集成在設備裏的客戶端庫,平臺端一般只有二次開發的需求。而設備端由於芯片、系統和指令集、內存限制等等因素,只提供客戶端庫或二進制可執行文件是不夠的,還可能需要客戶端開發者根據交互協議來自行開發客戶端組件。這就要求內網穿透組件提供客戶端與服務端的交互協議,且最好是設計爲非常簡單的協議。

2 CYarp出場

CYarp基於Yarp的http內網穿透中間件,支持tcp、http/2.0或http/3.0作爲http/1.1的傳輸層,其具有以下特徵

  1. 是一個標準的asp.netcore中間件
  2. 能完整使用asp.netcore框架和其它中間件
  3. 使用服務端的tls(https)做爲安全傳輸層
  4. 單連接多路複用,無需客戶端提供http2服務器
  5. 協議透明簡單,參考了WebSocket升級和Bootstrapping WebSockets with HTTP/2

2.1 服務端開發

CYarp中間件其依賴於Authentication身份認證中間件,使用如下方法進行註冊和中間件的配置。

builder.Services.AddCYarp(cyarp=>
{
    ...
});

中間件配置順序如下:

...
app.UseAuthentication();
...
app.UseCYarp();
...

最後在Controller、minapi的處理者或中間件中處理http轉發

// 請求者的授權驗證
[Authorize(Roles = "Mobile")]
public class CYarpController : ControllerBase
{ 
    private static readonly string clientIdClaimType = "ClientId";

    /// <summary>
    /// 處理cyarp
    /// 核心操作是從請求上下文獲取clientId
    /// 然後使用clientId從clientManager獲取client來轉發http
    /// </summary>
    /// <param name="clientManager"></param>
    /// <returns></returns>
    [Route("/{**cyarp}")]
    public async Task InvokeAsync([FromServices] IClientManager clientManager)
    {
        var clientId = this.User.FindFirstValue(clientIdClaimType);
        if (clientId != null && clientManager.TryGetValue(clientId, out var client))
        {
            this.Request.Headers.Remove(HeaderNames.Authorization);
            await client.ForwardHttpAsync(this.HttpContext);
        }
        else
        {
            this.Response.StatusCode = StatusCodes.Status502BadGateway;
        }
    }
}

2.2 客戶端開發

使用CYary.Client.CYarpClient很方便完成客戶端開發

 using var client = new CYarpClient();
 while (true))
 {
     await client.TransportAsync(this.clientOptions.CurrentValue, stoppingToken).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing);
 }

2.3 客戶端協議

由於篇幅有限,不在這裏展開,可以查閱CYarp握手協議

3 同源產品

Yarp是dotnet平臺下堪比nginx的一個組件,其它融入asp.netcore框架作爲裏面的中間件共享asp.netcore生態。

davidfowl大神也曾經小手一揮造就了YarpTunnelDemo項目,也是實現了http內網穿透的能力。但是他的實現方案要求客戶端方能要運行asp.netcore監聽做爲客戶端組件,由於asp.netcore的runtime只適配了桌面系統,且編譯出的二進制文件很大,此方法自然無法在物聯網設備中運行了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章