API 認證機制(Authentication)
是什麼?
API 認證(Authentication)是驗證「你是誰」的機制。不同的認證方式在安全性、複雜度、適用場景上各有取捨。JWT 適合無狀態認證、OAuth 2.0 適合第三方授權、API Key 適合服務間通訊。
ℹ️認證 vs 授權
Authentication(認證)= 你是誰?驗證身份。Authorization(授權)= 你能做什麼?檢查權限。認證在前,授權在後。本篇聚焦認證,授權會在 IAM 章節深入討論。
核心觀念
- JWT(JSON Web Token):由三段 Base64 編碼組成(Header.Payload.Signature),伺服器用密鑰簽名,不需查資料庫即可驗證。包含使用者資訊(claims),有過期時間
- OAuth 2.0:授權框架(不是認證協議),定義了四種授權流程(Grant Types)。核心角色:Resource Owner、Client、Authorization Server、Resource Server
- API Key:一組隨機字串,通常放在 Header 或 Query 中。簡單但缺乏細緻的權限控制
- Refresh Token:JWT 過期後用 Refresh Token 換新的 Access Token,避免使用者頻繁重新登入
- Bearer Token:放在
Authorization: Bearer <token>Header 中傳送的認證令牌
常見誤區
⚠️常見誤區
- 把敏感資料放在 JWT Payload:JWT 的 Payload 只是 Base64 編碼(不是加密),任何人都能解碼讀取。不要放密碼、信用卡號等敏感資訊
- JWT 不設過期時間:沒有過期時間的 JWT 一旦洩漏就永久有效。Access Token 建議 15-60 分鐘過期
- 用 API Key 做使用者認證:API Key 適合服務對服務(S2S)通訊,不適合終端使用者認證(因為無法追蹤個別使用者)
流程/步驟
使用者登入
送出帳號密碼到 /auth/login
伺服器驗證
比對密碼 Hash,驗證身份
產生 Token
簽發 JWT Access Token + Refresh Token
客戶端儲存
Access Token 存記憶體,Refresh Token 存 HttpOnly Cookie
帶 Token 請求
每次 API 請求帶 Authorization: Bearer token
Token 過期換新
用 Refresh Token 換新的 Access Token
流程解讀:使用者登入後取得一對 Token。Access Token 短效(15-60 分鐘)放在請求 Header 中,Refresh Token 長效(7-30 天)安全儲存在 HttpOnly Cookie。Access Token 過期時用 Refresh Token 無感刷新。
程式碼範例
C# 版本
// ASP.NET Core — JWT 認證設定
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = "https://api.example.com",
ValidateAudience = true,
ValidAudience = "https://app.example.com",
ValidateLifetime = true,
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(config["Jwt:Secret"]!))
};
});
// 產生 JWT
public string GenerateToken(User user)
{
var claims = new[]
{
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Email, user.Email),
new Claim(ClaimTypes.Role, user.Role)
};
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_secret));
var token = new JwtSecurityToken(
issuer: "https://api.example.com",
audience: "https://app.example.com",
claims: claims,
expires: DateTime.UtcNow.AddMinutes(30),
signingCredentials: new SigningCredentials(key, SecurityAlgorithms.HmacSha256)
);
return new JwtSecurityTokenHandler().WriteToken(token);
}TypeScript 版本
// Express.js — JWT 認證
import jwt from "jsonwebtoken";
// 產生 Token
function generateToken(user: User): string {
return jwt.sign(
{ userId: user.id, email: user.email, role: user.role },
process.env.JWT_SECRET!,
{ expiresIn: "30m", issuer: "https://api.example.com" }
);
}
// 驗證 Middleware
function authMiddleware(req: Request, res: Response, next: NextFunction) {
const token = req.headers.authorization?.replace("Bearer ", "");
if (!token) return res.status(401).json({ error: "No token provided" });
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET!);
req.user = decoded;
next();
} catch {
res.status(401).json({ error: "Invalid or expired token" });
}
}
// 保護路由
app.get("/api/profile", authMiddleware, (req, res) => {
res.json({ user: req.user });
});Python 版本
# FastAPI — JWT 認證
from jose import jwt, JWTError
from datetime import datetime, timedelta
from fastapi import Depends, HTTPException
from fastapi.security import HTTPBearer
security = HTTPBearer()
SECRET_KEY = "your-secret-key"
def create_access_token(user_id: int, role: str) -> str:
payload = {
"sub": str(user_id),
"role": role,
"exp": datetime.utcnow() + timedelta(minutes=30),
}
return jwt.encode(payload, SECRET_KEY, algorithm="HS256")
async def get_current_user(credentials=Depends(security)):
try:
payload = jwt.decode(credentials.credentials, SECRET_KEY, algorithms=["HS256"])
return payload
except JWTError:
raise HTTPException(status_code=401, detail="Invalid token")
@app.get("/api/profile")
async def profile(user=Depends(get_current_user)):
return {"user": user}架構圖/概念圖
使用者用帳密向 Auth Server 認證,取得 Access Token 和 Refresh Token。之後每次請求 API 帶上 Access Token。Token 過期時用 Refresh Token 向 Auth Server 換新的 Access Token。
實戰補充
Q: JWT 的 Secret Key 該怎麼管理?
A: 不要硬寫在程式碼中。用環境變數或 Secret Manager(如 Azure Key Vault、AWS Secrets Manager)管理。生產環境的 Key 長度至少 256 bits。考慮用 RSA 非對稱加密(RS256)取代對稱加密(HS256),這樣驗證方只需公鑰。
Q: OAuth 2.0 的四種 Grant Type 怎麼選?
A: Authorization Code:Web App、有後端的 SPA(最安全)。Authorization Code + PKCE:純前端 SPA、Mobile App。Client Credentials:服務對服務(S2S)。Implicit 和 Resource Owner Password 已不推薦使用。
Q: 為什麼不用 localStorage 存 Token?
A: localStorage 容易被 XSS 攻擊讀取。Refresh Token 建議存在 HttpOnly + Secure + SameSite Cookie 中。Access Token 可存在記憶體(JavaScript 變數)中。
理解測驗
🤔 JWT 的 Payload 是加密的嗎?
🤔 服務對服務(S2S)的認證最適合用哪種方式?
🤔 Access Token 建議的過期時間是多長?
重點整理
💡一句話記住
JWT 無狀態驗身份、OAuth 委託授權、API Key 簡單但粗。 口訣:「短命 Access、長命 Refresh、密鑰不寫死」
| 方式 | 適用場景 | 優點 | 缺點 | |------|---------|------|------| | JWT | 使用者認證、微服務間 | 無狀態、不查 DB | 無法即時撤銷 | | OAuth 2.0 | 第三方登入、授權 | 標準化、細粒度授權 | 複雜度高 | | API Key | S2S、公開 API | 簡單 | 無法追蹤使用者 |