HTTP Basic Auth 是最簡單的認證機制,適合內部 API、測試環境、簡單管理後台。本文展示標準實作、中介軟體封裝、安全性注意事項與現代替代方案對比。
<?php
function requireBasicAuth(string $realm = 'Restricted Area', callable $validator): void {
// 1. 檢查是否已提供認證頭
if (!isset($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'])) {
challenge($realm);
}
$username = $_SERVER['PHP_AUTH_USER'];
$password = $_SERVER['PHP_AUTH_PW'];
// 2. 驗證 (回傳 true/false 或拋出異常)
if (!$validator($username, $password)) {
challenge($realm);
}
// 3. 認證通過,可選:將用戶資訊存入全域
$GLOBALS['AUTH_USER'] = $username;
}
function challenge(string $realm): never {
header('WWW-Authenticate: Basic realm="' . $realm . '"');
header('HTTP/1.0 401 Unauthorized');
header('Content-Type: text/plain; charset=utf-8');
exit('Authentication required');
}
// 使用範例
requireBasicAuth('Admin Panel', function($user, $pass) {
// 實際應從資料庫查詢並 password_verify()
return $user === 'admin' && $pass === 'secure-password-from-env';
});
echo "Welcome, {$GLOBALS['AUTH_USER']}!";
?>
<?php
namespace App\Http\Middleware;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
class BasicAuthMiddleware implements MiddlewareInterface {
public function __construct(
private string $realm,
private callable $validator // ($username, $password) => bool|UserObject
) {}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface {
$auth = $request->getHeaderLine('Authorization');
if (!$auth || !preg_match('/^Basic\s+(.+)$/i', $auth, $matches)) {
return $this->challenge();
}
$decoded = base64_decode($matches[1]);
if ($decoded === false || !str_contains($decoded, ':')) {
return $this->challenge();
}
[$username, $password] = explode(':', $decoded, 2);
$result = ($this->validator)($username, $password);
if (!$result) {
return $this->challenge();
}
// 將用戶物件注入請求屬性,後續控制器可取用
$request = $request->withAttribute('auth.user', $result);
return $handler->handle($request);
}
private function challenge(): ResponseInterface {
$response = new \Laminas\Diactoros\Response\TextResponse('Authentication required', 401);
return $response->withHeader('WWW-Authenticate', 'Basic realm="' . $this->realm . '"');
}
}
// 路由註冊範例 (Slim 4)
$app->group('/api/admin', function($group) {
$group->get('/users', UserController::class . ':list');
})->add(new BasicAuthMiddleware('Admin API', function($u, $p) {
return UserService::verify($u, $p); // 回傳 User 物件或 false
}));
?>
| 風險 | 對策 |
|---|---|
| 明文傳輸 (Base64 非加密) | 強制 HTTPS,否則帳密等同裸奔 |
| 暴力破解 | 限流 (Rate Limit)、失敗鎖定、CAPTCHA、雙因子認證 (2FA) |
| 憑證洩露 | 密碼用 password_hash() 儲存,嚴禁明文/可逆加密 |
| CSRF | Basic Auth 無 CSRF 風險 (瀏覽器不自動發送),但若混用 Cookie 需防禦 |
| 快取敏感頁面 | 回應頭加 Cache-Control: no-store, private |
| 登出困難 | 瀏覽器無標準登出 API,通常靠關閉瀏覽器或修改 realm 強制重新認證 |
| 方案 | 優點 | 缺點 | 適用場景 |
|---|---|---|---|
| JWT (JSON Web Token) | 無狀態、跨域、攜帶聲明、標準化 | 無法撤銷 (需黑名單)、Payload 可解碼、簽名驗證開銷 | SPA、微服務、行動端 API |
| OAuth 2.0 / OpenID Connect | 授權碼模式、第三方登入、權限範圍、刷新令牌 | 實作複雜、需授權伺服器 | 開放平台、SSO、多應用生態 |
| API Key / Bearer Token | 簡單、可撤銷、適合機器對機器 | 無用戶身份語意、需自行管理權限 | 內部服務通訊、Webhook 驗證 |
| Session + Cookie (傳統) | 成熟、支援 CSRF 保護、易撤銷 | 有狀態、需共享存儲 (Redis)、跨域麻煩 | 傳統網站、後台管理 |
| HTTP Basic Auth | 極簡、標準、無需 Cookie/JS、curl 友善 | 明文傳輸、無登出、無權限細粒度、UX 差 | 內部工具、測試環境、IoT 裝置、單機腳本 |
// 路由群組
Route::group(['middleware' => 'auth.basic'], function () {
Route::get('/api/user', function () {
return Auth::user();
});
});
// 自定義守衛 (用 email 而非 username)
Route::group(['middleware' => 'auth.basic:api'], function () { ... });
// config/auth.php
'guards' => [
'api' => [
'driver' => 'session', // 或 token
'provider' => 'users',
],
],
password_verify(),嚴禁自行比對哈希。HTTP Basic Auth 雖簡單,但安全邊界清晰:僅在「受信任網路 + HTTPS + 低頻存取」場景使用,其餘一律升級至現代認證體系。