跳至主要內容
Skip to content

檔案上傳系統設計 (10) —— 私有檔案的訪問控制

如果你開發的是像「大頭貼」或「產品插圖」這樣的功能,公網直接訪問路徑(https://cdn.example.com/uploads/me.jpg)是沒問題的。

但如果你處理的是「合約 PDF」、「用戶的身分證掃描」或者是「付費課程影片」,事情就完全不一樣了。你絕對不能讓任何知道路徑的人都能下載這些檔案。

本篇將介紹如何從架構層面實作 私有檔案的訪問控制 (Access Control)


一、 核心概念:Public vs Private Storage

第一步是將開發思維進行隔離。

  • Public Bucket:存放一般靜態資源,讀取權限設為 public-read
  • Private Bucket:存放敏感檔案,讀取權限設為 private,拒絕所有匿名請求。

二、 方案 A:預簽名訪問 URL (Cloud Native)

這是利用雲端服務(如 S3/GCS)最優雅的做法。

運作流程:

  1. 檔案儲存在 S3,設為私有。
  2. 前端請求查看照片。
  3. 後端 API 檢查該用戶是否有權限。
  4. 如果授權通過,後端向 S3 申請一個有效期(例如 5 分鐘)的 Signed Download URL
  5. 前端拿到這組帶有加密簽章的 URL 即可直接加載圖片。

> **優點**:不消耗你的伺服器頻寬,且 URL 過期後即失效,防止用戶私下傳送連結。


三、 方案 B:應用程式代傳 (Proxy Streaming)

如果你你是使用本地硬碟儲存,或不想暴露 S3 資訊,可以使用轉傳模式。

實作範例 (Node.js):

javascript
app.get("/private/:fileId", async (req, res) => {
  // 1. 權限檢查
  const userHasPermission = await checkAuth(req.user, req.params.fileId);
  if (!userHasPermission) return res.status(403).send("拒絕訪問");

  // 2. 獲取檔案路徑
  const file = await db.files.find(req.params.fileId);
  const filePath = path.resolve(file.full_path);

  // 3. 串流輸出
  const stream = fs.createReadStream(filePath);
  res.setHeader("Content-Type", file.mime_type);
  stream.pipe(res);
});

四、 進階:高效的安全轉發 (X-Accel-Redirect)

上述「方案 B」的 Node.js 串流雖然簡單,但會佔用 Node.js 的 CPU 與運算資源。

如果你使用 Nginx,可以使用一個強大的技巧:X-Accel-Redirect

  1. Node.js 處理 API,檢查權限。
  2. 權限通過後,Node.js 回傳一個 Header:X-Accel-Redirect: /internal/file/path
  3. Nginx 攔截此 Header,並「在內部」直接從硬碟讀取檔案傳給用戶。

結果:Node.js 負責「安全門禁」,Nginx 負責「搬運工」。這能讓單機效能發揮到極致。


總結

保護私有檔案的原則:

  1. 儲存隔離:不要把私有檔案跟公開檔案混在一起。
  2. 門禁制度:每一次訪問都必須經過 API 的身份驗證。
  3. 時效授權:儘量使用帶有效期的簽名連結。

至此,我們完成了本系列第二階段「整合實戰與體驗」。目前你的系統已經具備了強大的上傳、處理、優化與保護能力。


️ 進階挑戰

嘗試使用 JWT 或 Session 機制實作一個簡單的檔案下載門禁。如果 Token 過期,伺服器應該回傳什麼樣的 HTTP 狀態碼?


延伸閱讀與資源

← 上一章:多媒體處理流水線 | 返回專案首頁 | 下一章:檔案生命週期管理