快速開始
最後更新
本頁從安裝到完成第一次登入、驗證與登出,串起一個可執行的 Express 應用。
前置需求
| 項目 | 需求 |
|---|---|
| Node.js | 20 以上(package.json engines) |
| Express | 4.18 以上(peer dependency) |
| Redis | 可連線的 Redis 伺服器 |
| Cookie 解析 | cookie-parser 或同等中介軟體;套件從 req.cookies 讀取 Token |
| 金鑰 | EC P-256 金鑰對;簽章演算法固定為 ES256 |
安裝
npm install @pardnchiu/jwt-auth express cookie-parser
產生 ES256 金鑰
mkdir -p keys
openssl ecparam -name prime256v1 -genkey -noout -out keys/private.pem
openssl ec -in keys/private.pem -pubout -out keys/public.pem
RSA 或 HMAC 金鑰無法以 ES256 簽章,CreateJWT() 會拋出錯誤。
第一個應用
import express, { Request, Response, NextFunction } from "express";
import cookieParser from "cookie-parser";
import { JWTAuth } from "@pardnchiu/jwt-auth";
const app = express();
app.use(express.json());
app.use(cookieParser());
async function requireAuth(req: Request, res: Response, next: NextFunction) {
try {
const result = await JWTAuth.VerifyJWT(req, res);
if (!result.isAuth) {
// isError 為 true 代表可疑請求,否則為一般訪客
return res.status(result.isError ? 400 : 401).json({ error: "unauthorized" });
}
res.locals.user = result.data;
next();
} catch (err) {
res.status(500).json({ error: (err as Error).message });
}
}
app.post("/login", async (req, res) => {
try {
// 帳密驗證完成後簽發 Token
const result = await JWTAuth.CreateJWT(req, res, {
id: "user123",
name: "John",
email: "john@example.com",
});
res.json(result);
} catch (err) {
res.status(500).json({ error: (err as Error).message });
}
});
app.get("/me", requireAuth, (req, res) => {
res.json({ user: res.locals.user });
});
app.post("/logout", async (req, res) => {
await JWTAuth.RevokeJWT(req, res);
res.json({ ok: true });
});
async function main() {
await JWTAuth.init({
privateKeyPath: "./keys/private.pem",
publicKeyPath: "./keys/public.pem",
accessTokenExpires: 900,
refreshTokenExpires: 604800,
isProd: false,
AccessTokenCookieKey: "access_token",
RefreshTokenCookieKey: "refresh_id",
redis: { host: "localhost", port: 6379 },
checkUserExists: async (userId) => true,
});
app.listen(3000);
}
main().catch((err) => {
// 金鑰讀取失敗或 Redis 無法連線
console.error(err);
process.exit(1);
});
驗證是否運作
curl -i -c jar.txt -X POST http://localhost:3000/login
curl -i -b jar.txt http://localhost:3000/me
curl -i -b jar.txt -X POST http://localhost:3000/logout
curl -i -b jar.txt http://localhost:3000/me
isProd: false 時 cookie 的 domain 固定為 localhost,請以 http://localhost 而非 127.0.0.1 存取,否則瀏覽器與 curl 都不會回送 cookie。
下一步
- Token 何時續期、何時換發:Refresh Token 輪替
- 所有設定欄位:設定
- 行動 App 等非瀏覽器客戶端:客戶端整合