HTTP Basic Authentication 白話教學

Published December 15, 2025 by 徐培鈞
基礎概念

在前面的單元,我們學過 API Key 這種驗證方式。

API Key 很單純,就是一把金鑰,有鑰匙就能進門。

但 API Key 比較適合 Server to Server 的情境,也就是後端伺服器之間的溝通。

那如果我們想做 Client to Server 呢?例如讓使用者從瀏覽器直接驗證身份,這時候該怎麼辦?

這就是今天要介紹的 HTTP Basic Authentication(基本認證)。

API Key 的限制

在講 Basic Auth 之前,我們先回想一下 API Key 有什麼問題。

API Key 就像一把鑰匙:

  • 你有鑰匙 → 可以進門
  • 你沒鑰匙 → 滾

但問題是:你不知道拿著鑰匙的人是誰

小明拿這把鑰匙可以進門,老王拿同一把鑰匙也可以進門,系統根本分不出來。

如果我們想要做「多用戶管理」,想知道現在是誰在用系統,API Key 就做不到了。

為什麼會這樣?這要從 API Key 的使用情境說起。

API Key 最常用在 Server to Server 的情境,也就是後端伺服器之間的溝通。

例如你的伺服器要去呼叫金流 API、寄信 API,這種情境下,發請求的永遠是「你的程式」,不會有其他人,所以一把 Key 就夠了。

但如果是 Client to Server 的情境就不一樣了。例如你做了一個內部後台,讓小明、老王、阿華三個同事從瀏覽器登入使用。

這時候發請求的是「人」,而且是「很多不同的人」。

你會想知道:這筆操作是誰做的?這筆資料是誰改的?

API Key 沒辦法告訴你這些,因為它只是一把鑰匙,不帶任何身份資訊。

這時候就可以用 Basic Auth 來解決這個問題。

Basic Auth 怎麼運作的?

放在 HTTP Header 裡面

在講 Basic Auth 怎麼傳遞之前,先快速複習一下 HTTP Header。

每次你發送 HTTP 請求的時候,除了網址跟資料本身,還會有一個「Header」區塊,可以放各種附加資訊。

HTTP 規範裡面已經定義好很多標準的 Header,例如:

  • Content-Type:告訴伺服器我傳的資料是什麼格式(JSON、HTML…)
  • Content-Length:告訴伺服器資料有多大
  • Host:告訴伺服器我要連的是哪個網站

這些都是「標準 Header」,HTTP 規範裡本來就有的。

但有時候你想傳一些規範裡沒有的東西,就可以自己定義 Header。慣例上會用 X- 開頭,表示這是「自訂的」。

還記得 API Key 是怎麼傳的嗎?API Key 通常就是用自訂的 Header

X-API-Key: your-api-key-here

這個 X-API-Key 不是 HTTP 標準,是大家約定俗成自己取的名字。

但 Basic Auth 不一樣,它用的是 HTTP 規範裡原本就有的標準 HeaderAuthorization

Authorization: Basic xxxxxxxxxx

這裡有三個部分:

  1. Authorization:HTTP 標準的 Header,專門用來做身份驗證
  2. Basic:告訴伺服器「我用的是 Basic 這種驗證方式」(之後學到 JWT,這裡會換成 Bearer
  3. xxxxxxxxxx:這是你的帳號密碼(經過處理的,下面會講)

Token 是怎麼來的?

那個 xxxxxxxxxx 其實是這樣組成的:

帳號:密碼    Base64 編碼    Token

舉個例子:

kk:1234    Base64 編碼    a2s6MTIzNA==

所以最後送出去的 Header 是:

Authorization: Basic a2s6MTIzNA==

為什麼要 Base64 編碼?

你可能會問:「幹嘛多此一舉?直接傳帳號密碼不就好了?」

問題是,有些人的密碼很「有個性」:

  • 密碼裡有空白
  • 密碼裡有 @#$% 這些符號
  • 密碼裡有中文

這些「奇怪的字」在 HTTP 傳輸時可能會出包。

所以我們用 Base64 編碼,把它轉成「安全的字」(只有英文字母、數字、加號、斜線、等號),這樣傳輸就不會有問題了。

記住:Base64 是「編碼」不是「加密」,可以輕鬆解回來,所以不要以為這樣就安全了!

所以 Basic Auth 怎麼解決 API Key 的問題?

現在你知道 Basic Auth 的 Token 裡面包含了「帳號」和「密碼」。

這就是它跟 API Key 最大的差別:

  • kk + 1234 → 伺服器知道是 kk 本人
  • ken + 5678 → 伺服器知道是 ken 本人
  • 亂打的 → 掰掰

因為有帳號,所以可以做「多用戶管理」,知道是誰在用你的系統。

Challenge 機制:那個醜醜的彈窗

帳號密碼從哪裡來?

前面我們講了 Basic Auth 是透過 HTTP Header 傳送 Token,Token 裡面包含帳號和密碼。

但這邊有一個問題:這個帳號密碼要從哪裡來?

如果是 Server to Server 的情境,你可以把帳號密碼寫在後端程式或環境變數裡,反正使用者看不到。

但如果是 Client to Server 呢?例如使用者從瀏覽器發請求,你總不能把帳號密碼寫死在前端 JavaScript 裡吧?那任何人打開原始碼都看得到,超不安全。

所以有了 Challenge 機制

為了解決這個問題,Basic Auth 有一個機制叫 Challenge(挑戰)。

運作方式是這樣的:

  1. 使用者嘗試進入某個受保護的頁面
  2. 伺服器發現你沒有提供帳號密碼,就回傳一個「401 未授權」的狀態
  3. 瀏覽器收到這個回應後,自動跳出一個視窗問你帳號密碼
  4. 你填完之後,瀏覽器自動幫你把帳號密碼編碼成 Token,放進 Header 重新發送請求

白話來說就是:

伺服器跟瀏覽器說:「欸,你要進來喔?先告訴我你的帳號密碼!」

然後瀏覽器就自動跳出一個視窗問你。

長什麼樣子?

就是那個你在一些老網站或內部系統會看到的彈窗:

對,就是那個看起來很復古的東西。

Challenge 的好處

  • 不用自己寫登入頁面
  • 不用把帳號密碼寫死在程式裡
  • 瀏覽器原生支援,超省事

伺服器怎麼存帳號密碼?

先講驗證流程

當使用者輸入帳號密碼後,瀏覽器會把它編碼成 Token,放進 HTTP Header 送出去。

收到請求的一方會:

  1. 從 Header 拿出 Token
  2. 用 Base64 解碼,得到 帳號:密碼
  3. 去「某個地方」比對,對了就放行,錯了就拒絕

那個「某個地方」是哪裡?通常有兩種做法。

方法一:存在資料庫

在資料庫建一張表,存所有使用者的帳號密碼:

users 資料表
─────────────────────────
| username | password    |
|----------|-------------|
| kk       | 1234        |
| ken      | 5678        |
| admin    | secret      |
─────────────────────────

你的後端程式收到請求後,就去資料庫查有沒有這組帳密。

適合: 使用者很多、常常變動、需要細緻的權限控制

代價: 要架資料庫、要寫驗證邏輯

方法二:寫在檔案裡(讓反向代理幫你擋)

在正式環境中,請求通常會先經過反向代理:

使用者  Nginx(反向代理)  Express/Django(後端程式)

你可以讓 Nginx 在最前面就擋掉,根本不讓請求進到你的程式。

怎麼做?在伺服器上放一個 .htpasswd 檔案:

kk:1234
ken:5678
admin:secret

這個檔案是放在「伺服器主機」上的,不是放在你的程式碼 repo 裡。

舉個例子,你把網站部署到一台 Linux 伺服器上,你可以把 .htpasswd 放在某個路徑,例如 /etc/nginx/.htpasswd

然後在 Nginx 的設定檔裡面,告訴它:「如果有人要進這個頁面,去讀 /etc/nginx/.htpasswd 這個檔案比對帳密。」

location /admin {
    auth_basic "請輸入帳號密碼";
    auth_basic_user_file /etc/nginx/.htpasswd;
}

這樣 Nginx 就會自動幫你驗證,你的程式碼完全不用動。

適合: 使用者很少、幾乎不會變、懶得寫程式

代價: 改帳密要手動編輯檔案、沒辦法做細緻的權限控制

怎麼選?

簡單講:

  • 想省事、使用者少 → 用檔案
  • 要彈性、使用者多 → 用資料庫

Basic Auth 的致命缺點

講了這麼多好處,該來潑冷水了。

Base64 不是加密!

前面說過,Base64 是「編碼」,任何人拿到你的 Token 都可以輕鬆解碼:

a2s6MTIzNA==    解碼    kk:1234

所以如果有人在網路上攔截你的請求,你的帳號密碼就直接被看光光了。

一定要配 HTTPS!

這點超級重要:永遠不要在沒有 HTTPS 的情況下用 Basic Auth!

  • HTTP(沒加密)→ 裸奔,超危險 ❌
  • HTTPS(有加密)→ 至少傳輸過程是安全的 ✅

快速看一下怎麼寫

前端 JavaScript

const username = 'kk';
const password = '1234';

// 組合並編碼
const token = btoa(`${username}:${password}`);

// 發送請求
fetch('https://api.example.com/data', {
  headers: {
    'Authorization': `Basic ${token}`
  }
});

用 cURL 測試

# 最簡單的寫法
curl -u kk:1234 https://api.example.com/data

什麼時候該用 Basic Auth?

先釐清一個常見的疑惑

學到這裡,你可能會想:

「咦?Basic Auth 要輸入帳號密碼,我們公司的會員系統也是輸入帳號密碼,這不是一樣的東西嗎?」

答案是:不一樣!

最大的差別在於:有沒有登入頁面

一般會員登入系統有漂亮的登入頁面
Basic Auth瀏覽器跳出醜醜的彈窗
一般會員登入系統要自己做登入頁、處理 Session
Basic Auth幾乎不用寫前端
一般會員登入系統對外的網站、App
Basic Auth內部系統、後台工具

Basic Auth 的定位

想像一個情境:

你做了一個公司內部的「數據後台」,只給幾個同事看。

為了這個後台,你還要特地做一個會員系統?寫登入頁面?處理忘記密碼?

太累了吧!我只是想「擋一下」而已啊!

這時候 Basic Auth 就超好用!

你只要在後台頁面前面加一層「門禁」(技術上叫 Middleware,之後會學到),設定好哪些帳號密碼可以進來,瀏覽器就會自動跳出一個小視窗問你帳密。

不用寫登入頁面、不用做會員系統,幾行設定就搞定。

適合 vs 不適合

適合用 Basic Auth:

  • 公司內部系統
  • 開發測試用的 API
  • 簡單的小工具後台
  • 臨時擋一下的需求

不適合用 Basic Auth:

  • 對外開放的網站
  • 有敏感資料的系統
  • 正式的產品環境

說白了,Basic Auth 就是懶人擋一下的好工具,但不適合拿來做正式的會員系統。

總結

一張圖看懂 Basic Auth

記住這幾點就夠了

  1. Basic Auth = 帳號 + 密碼,可以知道是誰在用
  2. 用 Base64 編碼,處理特殊字元問題
  3. 有 Challenge 機制,會跳彈窗問你帳密
  4. 適合內部系統,不想寫登入頁面的時候很好用
  5. 一定要配 HTTPS,不然帳密會被看光
  6. 跟會員系統不一樣,Basic Auth 是懶人擋一下的好工具

什麼時候用 Basic Auth?

當你懶得做登入頁面,只想快速擋一下的時候,Basic Auth 是你的好朋友。

但如果是正式的產品,建議學一下 JWT 或 OAuth 2.0,那才是現在業界主流的做法。

延伸學習

學完 Basic Auth,接下來可以看看:

  • JWT:現在最流行的 Token 驗證方式
  • OAuth 2.0:第三方登入都在用這個(像是「用 Google 帳號登入」)
  • Session-based Auth:傳統網站的登入機制