🔑 實作 API Key 驗證:讓客戶付費買你的 API
在前面的章節中,我們都是扮演「呼叫別人 API」的角色(例如打 Stripe、打綠界、打 OpenAI)。 但如果你自己寫出了一個超強的 AI 圖片生成模型、或是一個非常精準的股市預測演算法,你想要把它做成 API,開放給全世界的工程師付費使用,你該怎麼做?
這時候,你需要建立一套**「API Key 驗證系統」**!
本章將帶你從零到一實作一套商業級的 API Key 邏輯,包含:產生金鑰、驗證身分,以及計算使用額度!
1. 什麼是 API Key?
API Key 就是一組難以猜測的長字串(例如 sk_live_abc123def456...)。
當客戶付錢給你後,你給他這組 Key。以後他呼叫你的 API 時,必須在 HTTP Header 裡面帶著這把 Key。你的後端只要看到這把 Key,就知道「哦!這是王大明的請求,扣他 1 點額度」。
資料庫設計 (PostgreSQL 範例)
為了管理 API Key,我們需要在資料庫建立一張關聯表:
CREATE TABLE api_keys (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID REFERENCES users(id), -- 這是誰的 Key
key_value VARCHAR(255) UNIQUE NOT NULL, -- 實際的字串 (例如 sk_live_...)
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW(),
last_used_at TIMESTAMP WITH TIME ZONE,
is_active BOOLEAN DEFAULT TRUE,
usage_count INTEGER DEFAULT 0 -- 呼叫次數統計
);
2. 產生一把安全的 API Key
API Key 絕對不能是循序漸進的(例如 001, 002),否則駭客隨便猜就猜到了。
我們可以使用 Node.js 內建的 crypto 模組,來產生一把隨機且安全的字串。
// src/app/api/generate-key/route.ts
import { NextResponse } from 'next/server';
import crypto from 'crypto';
import { db } from '@/lib/db'; // 你的資料庫連線
// 產生隨機字串的 Helper Function
function generateApiKey() {
// 產生 32 bytes 的隨機十六進位字串,前面加上自定義的 prefix
const randomStr = crypto.randomBytes(32).toString('hex');
return `vibe_sk_${randomStr}`;
}
export async function POST(request: Request) {
// 假設你有驗證使用者是否登入
const userId = 'user-123';
const newKey = generateApiKey();
// 存入資料庫
const insertedKey = await db.api_keys.insert({
user_id: userId,
key_value: newKey,
is_active: true
});
return NextResponse.json({
message: "API Key 建立成功!請妥善保存,它只會顯示這一次。",
apiKey: newKey
});
}
⚠️ 資安實踐:在業界最嚴格的做法中,資料庫不應該儲存明文的 API Key,而是儲存
hash(API Key)。這就像密碼一樣,即使資料庫被盜,駭客也拿不到原始的金鑰。但在小型專案中,儲存明文或是加密儲存是可以接受的權衡。
3. 在你的核心 API 中實作「驗證大門」
現在客戶拿到 vibe_sk_xxx... 這把鑰匙了。
當他來呼叫你那支會賺錢的「AI 股市預測 API」時,我們必須在門口設下警衛檢查。
業界標準的做法是:請客戶將 API Key 放在 HTTP Header 的 Authorization: Bearer <API_KEY> 裡面。
// src/app/api/stock-predict/route.ts
import { NextResponse } from 'next/server';
import { db } from '@/lib/db';
export async function POST(request: Request) {
// 1. 從 Header 取出 Authorization 欄位
const authHeader = request.headers.get('Authorization');
// 檢查格式是否正確 (Bearer vibe_sk_...)
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return NextResponse.json({ error: "Missing or invalid API Key format. Use 'Bearer <YOUR_KEY>'" }, { status: 401 });
}
// 取出真正的金鑰字串
const providedKey = authHeader.split(' ')[1];
// 2. 去資料庫比對這把鑰匙
const keyRecord = await db.api_keys.findUnique({
where: { key_value: providedKey }
});
// 如果鑰匙不存在,或是被停用了
if (!keyRecord || !keyRecord.is_active) {
return NextResponse.json({ error: "Invalid or inactive API Key" }, { status: 403 });
}
// 3. 檢查使用者的付費額度是否足夠 (可選)
const user = await db.users.findUnique({ where: { id: keyRecord.user_id }});
if (user.credits <= 0) {
return NextResponse.json({ error: "Insufficient credits. Please top up your account." }, { status: 402 });
// 402 是 Payment Required,超適合這裡用!
}
// ------------------------------------
// 執行你真正值錢的商業邏輯
// ------------------------------------
const predictionResult = { stock: "TSLA", trend: "UP", confidence: 0.95 };
// 4. 執行完畢,扣除點數並更新統計
await db.users.update({
where: { id: user.id },
data: { credits: user.credits - 1 }
});
// 順便記錄這把 Key 的最後使用時間與次數
await db.api_keys.update({
where: { id: keyRecord.id },
data: {
usage_count: keyRecord.usage_count + 1,
last_used_at: new Date()
}
});
// 5. 滿載而歸的 Response!
return NextResponse.json({
data: predictionResult,
meta: {
credits_remaining: user.credits - 1
}
});
}
4. 客戶端如何呼叫你的 API?
有了這道完美的大門,現在你可以理直氣壯地寫出你的 API 官方文件了! 教你的客戶用以下的方式來呼叫:
用 Fetch (JavaScript/TypeScript):
const response = await fetch('https://api.yourdomain.com/stock-predict', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
// 這裡放上客戶花大錢買的 API Key!
'Authorization': 'Bearer vibe_sk_abc123...'
},
body: JSON.stringify({ symbol: "TSLA" })
});
const data = await response.json();
用 cURL (終端機):
curl -X POST https://api.yourdomain.com/stock-predict \
-H "Content-Type: application/json" \
-H "Authorization: Bearer vibe_sk_abc123..." \
-d '{"symbol": "TSLA"}'
太棒了!你現在已經擁有了一套完整的 B2B (企業對企業) SaaS 商業架構!只要你能寫出有價值的演算法,搭配這套 API Key 驗證機制,你就能坐在家裡看著呼叫次數 (usage_count) 不斷飆高,等著每個月向客戶收費了!💸