Khóa API giống như chìa khóa mở cửa cho dịch vụ của bạn—chúng cho phép người dùng truy cập trong khi vẫn đảm bảo an toàn cho mọi thứ. Trong blog này, tôi sẽ hướng dẫn bạn cách xây dựng trình tạo khóa API đơn giản, an toàn bằng cách sử dụng Upstash Redis để lưu trữ dữ liệu nhanh chóng, không cần máy chủ và Cloudflare Workers để xử lý các yêu cầu ở biên. Cho dù bạn đang thiết lập một dịch vụ mới hay thêm khóa vào ứng dụng hiện có, bạn sẽ tìm hiểu cách tạo, lưu trữ và xác thực khóa API để đảm bảo mọi thứ hoạt động trơn tru và hiệu quả.
Khóa API là gì?
Khóa API là một mã duy nhất xác định và xác thực người dùng hoặc ứng dụng đang cố truy cập API của bạn. Hãy coi nó giống như thẻ thông hành cá nhân:khi ai đó muốn sử dụng dịch vụ của bạn, họ cần hiển thị “chìa khóa” này để chứng minh rằng họ được phép truy cập. Khóa API giúp bạn kiểm soát ai có thể truy cập tài nguyên của mình và chúng thường được sử dụng để theo dõi việc sử dụng, thực thi các giới hạn hoặc ngăn chặn truy cập trái phép. Đây là cách đơn giản để quản lý quyền truy cập API và giữ an toàn cho dữ liệu của bạn.
Chúng tôi sẽ xây dựng những gì
Trong hướng dẫn này, chúng tôi sẽ tạo một trình tạo khóa api cung cấp hai chức năng cốt lõi:
- Tạo khóa API mới bằng cài đặt tùy chỉnh
- Xác thực khóa API trong khi truy xuất siêu dữ liệu của chúng
Các tính năng chính sẽ bao gồm:
- Tiền tố khóa có thể tùy chỉnh
- Ngày hết hạn
- Giới hạn tỷ lệ
- Lưu trữ siêu dữ liệu
- Nhận dạng chủ sở hữu
Hãy hình dung hệ thống khóa API của chúng tôi
Sơ đồ này minh họa sự tương tác giữa máy khách, Cloudflare Worker của chúng tôi và Upstash Redis trong cả việc tạo và xác thực khóa API. Với ý tưởng tổng quan này, hãy bắt đầu xây dựng hệ thống của chúng tôi.

Điều kiện tiên quyết
Để làm theo, bạn sẽ cần:
- Một Công nhân Cloudflare tài khoản
- Một Upstash tài khoản
- Node.js được cài đặt trên máy cục bộ của bạn
Cấu trúc dự án
Dự án của chúng ta sẽ có cấu trúc như sau:
folder-name/
├── src/
│ ├── config/
│ │ ├── generateApiKey.ts
│ │ └── schema-validation.ts
│ ├── lib/
│ │ └── ratelimit.ts
│ ├── routes/
│ │ ├── create.ts
│ │ └── verify.ts
│ ├── types/
│ │ └── api.ts
│ └── index.ts
├── package.json
└── wrangler.toml
Bước 1:Thiết lập dự án
Hãy bắt đầu bằng cách thiết lập dự án của chúng ta và cài đặt các phần phụ thuộc cần thiết.
Tạo thư mục dự án mới
Mở terminal của bạn và chạy các lệnh sau:
mkdir keyflow
cd keyflow
npm init -y Cài đặt phần phụ thuộc
Chúng tôi sẽ cần một vài gói cho dự án của mình:
npm install hono @upstash/redis @upstash/ratelimit @hono/zod-validator zod wrangler
@upstash/redis :Upstash Redis client cho môi trường serverless@upstash/ratelimit :Thư viện giới hạn tốc độ cho Upstash Redis@hono/zod-validator :Yêu cầu phần mềm trung gian xác thực cho Honozod :Thư viện xác thực lược đồ đầu tiên TypeScriptwrangler :CLI của Cloudflare dành cho phát triển và triển khai Công nhân
Thiết lập Upstash Redis
- Đăng nhập vào tài khoản Upstash của bạn và tạo cơ sở dữ liệu Redis mới

- Sau khi tạo, hãy điều hướng đến phần "API REST"

- Sao chép
UPSTASH_REDIS_REST_URLvàUPSTASH_REDIS_REST_TOKENtrong.envphần
Định cấu hình Cloudflare Worker
Tạo một wrangler.toml tập tin trong thư mục gốc dự án của bạn với nội dung sau:
name = "keyflow"
main = "src/index.ts"
compatibility_date = "2023-05-18"
[vars]
UPSTASH_REDIS_REST_URL = "your-redis-url"
UPSTASH_REDIS_REST_TOKEN = "your-redis-token"
Thay thế "your-redis-url" và "your-redis-token" với các giá trị bạn đã sao chép từ Upstash.
Bước 2:Xác định loại API
Hãy bắt đầu bằng cách xác định giao diện TypeScript cho các yêu cầu và phản hồi API của chúng tôi. Những loại này sẽ giúp chúng tôi duy trì sự an toàn về loại trong suốt ứng dụng của chúng tôi. Tạo một tệp mới src/types/api.ts :
export type CreateKeyRequest = {
apiId: string;
prefix?: string;
byteLength?: number;
ownerId?: string;
name: string;
meta?: Record<string, unknown>;
expires?: number;
ratelimit?: {
type: "fast" | "consistent";
limit: number;
refillRate: number;
refillInterval: number;
};
};
export type CreateKeyResponse = {
key: string;
keyId: string;
};
export type VerifyKeyRequest = {
key: string;
};
export type VerifyKeyResponse = {
valid: boolean;
ownerId?: string;
meta?: Record<string, unknown>;
expires?: number;
ratelimit?: {
limit: number;
remaining: number;
reset: number;
};
};
export type Env = {
UPSTASH_REDIS_REST_URL: string;
UPSTASH_REDIS_REST_TOKEN: string;
};
Bước 3:Triển khai tạo khóa API
Bây giờ, hãy tạo một hàm tiện ích để tạo khóa API. Tạo một tệp mới src/config/generateApiKey.ts :
export function generateApiKey(
prefix: string | undefined,
byteLength: number,
): string {
const randomBytes = crypto.getRandomValues(new Uint8Array(byteLength));
const key = btoa(String.fromCharCode(...new Uint8Array(randomBytes)))
.replace(/\+/g, "-")
.replace(/\//g, "_")
.replace(/=/g, "");
return prefix ? `${prefix}_${key}` : key;
}
Hàm này tạo khóa API ngẫu nhiên bằng cách sử dụng các byte ngẫu nhiên được bảo mật bằng mật mã, mã hóa khóa đó theo base64 và làm cho khóa đó an toàn với URL.
Bước 4:Thực hiện giới hạn tỷ lệ
Tạo một tệp src/lib/ratelimit.ts :
import { Ratelimit } from "@upstash/ratelimit";
import { Redis } from "@upstash/redis/cloudflare";
import type { Context, Next } from "hono";
import { env } from "hono/adapter";
import type { Env } from "../types/api";
// Middleware for rate limiting
export async function rateLimitMiddleware(c: Context, next: Next) {
const { UPSTASH_REDIS_REST_TOKEN, UPSTASH_REDIS_REST_URL } = env<Env>(c);
const redis = new Redis({
url: UPSTASH_REDIS_REST_URL,
token: UPSTASH_REDIS_REST_TOKEN,
});
const ratelimit = new Ratelimit({
redis: redis,
limiter: Ratelimit.slidingWindow(5, "30 s"),
});
const ip = c.req.header("CF-Connecting-IP") || "127.0.0.1";
const { success, limit, remaining, reset } = await ratelimit.limit(ip);
if (!success) {
return c.json({ error: "Rate limit exceeded" }, 429);
}
c.header("X-RateLimit-Limit", limit.toString());
c.header("X-RateLimit-Remaining", remaining.toString());
c.header("X-RateLimit-Reset", reset.toString());
await next();
} Bước 5:Tạo các tuyến API
Hãy thiết lập tệp ứng dụng chính của chúng tôi và tạo các tuyến API. Tệp này thiết lập ứng dụng Hono của chúng tôi với hai tuyến chính: /keys/create để tạo khóa API mới và /keys/verify để xác thực các khóa hiện có bằng ba tệp riêng biệt.
1. Triển khai Tạo lộ trình khóa API
Tạo một tệp src/routes/create.ts :
import { zValidator } from "@hono/zod-validator"
import { Redis } from "@upstash/redis/cloudflare"
import { Hono } from "hono"
import { generateApiKey } from "../config/generateApiKey"
import { createApiKeySchema } from "../config/schema-validation"
import type { CreateKeyRequest, CreateKeyResponse, Env } from "../types/api"
const create = new Hono<{
Bindings: Env
}>()
create.post(
"/create",
zValidator("json", createApiKeySchema, (result, c) => {
if (!result.success) {
return c.text("Invalid!", 400)
}
}),
async (c) => {
// Initialize Redis client
const { UPSTASH_REDIS_REST_TOKEN, UPSTASH_REDIS_REST_URL } = c.env
const redis = new Redis({
url: UPSTASH_REDIS_REST_URL,
token: UPSTASH_REDIS_REST_TOKEN,
})
const body = await c.req.json<CreateKeyRequest>()
// Generate unique identifier and API key
const keyId = crypto.randomUUID()
const key = generateApiKey(body.prefix, body.byteLength || 16)
const keyData = {
...body,
key,
keyId,
createdAt: Date.now(),
}
const encodedKey = encodeURIComponent(key)
try {
// Store key data and lookup reference in Redis
await redis.set(`key:${keyId}`, JSON.stringify(keyData))
await redis.set(`lookup:${encodedKey}`, keyId)
return c.json<CreateKeyResponse>({ key, keyId })
} catch (error) {
console.error("Error in /keys/create:", error)
return c.json({ error: "Internal Server Error" }, 500)
}
}
)
export default create 2. Triển khai Xác minh lộ trình khóa API
Tạo một tệp src/routes/verify.ts :
import { zValidator } from "@hono/zod-validator";
import { Redis } from "@upstash/redis/cloudflare";
import { Hono } from "hono";
import { verifyApiKeySchema } from "../config/schema-validation";
import type {
CreateKeyRequest,
Env,
VerifyKeyRequest,
VerifyKeyResponse,
} from "../types/api";
// Initialize Hono app with environment bindings
const verify = new Hono<{ Bindings: Env }>();
// Define POST route for verifying an API key
verify.post(
"/verify",
// Validate request body against schema
zValidator("json", verifyApiKeySchema, (result, c) => {
if (!result.success) {
return c.text("Invalid!", 400); // Return 400 if validation fails
}
}),
async (c) => {
// Set up Redis with environment variables
const { UPSTASH_REDIS_REST_TOKEN, UPSTASH_REDIS_REST_URL } = c.env;
const redis = new Redis({
url: UPSTASH_REDIS_REST_URL,
token: UPSTASH_REDIS_REST_TOKEN,
});
const body = await c.req.json<VerifyKeyRequest>();
if (!body.key) {
return c.json({ error: "key is required" }, 400); // Require key in the request body
}
const encodedKey = encodeURIComponent(body.key);
const keyId = await redis.get<string>(`lookup:${encodedKey}`); // Retrieve key ID using encoded key
if (!keyId) {
return c.json<VerifyKeyResponse>({ valid: false }); // Key not found
}
const keyDataString = await redis.get<string>(`key:${keyId}`); // Retrieve key data by key ID
if (!keyDataString || typeof keyDataString !== "string") {
return c.json<VerifyKeyResponse>({ valid: false }); // Key data missing or invalid
}
let keyData: CreateKeyRequest & {
key: string;
keyId: string;
createdAt: number;
};
try {
keyData = JSON.parse(keyDataString); // Parse key data
} catch (parseError) {
// Handle parse error by deleting invalid data
console.error("Key data parse error:", parseError);
await Promise.all([
redis.del(`key:${keyId}`),
redis.del(`lookup:${encodedKey}`),
]);
return c.json(
{
error: "Invalid key data in storage",
details: parseError instanceof Error ? parseError.message : "Unknown parse error",
valid: false,
},
500,
);
}
// Check if key has expired
if (keyData.expires && keyData.expires < Date.now()) {
await Promise.all([
redis.del(`key:${keyId}`),
redis.del(`lookup:${encodedKey}`),
]);
return c.json<VerifyKeyResponse>({ valid: false });
}
// Formulate response with validation status and metadata
const response: VerifyKeyResponse = {
valid: true,
ownerId: keyData.ownerId,
meta: keyData.meta,
expires: keyData.expires,
};
if (keyData.ratelimit) {
response.ratelimit = {
limit: keyData.ratelimit.limit,
remaining: keyData.ratelimit.limit,
reset: Date.now() + keyData.ratelimit.refillInterval,
};
}
return c.json(response); // Return verification response
},
);
export default verify;
3. Triển khai tệp chính index.ts
triển khai tệp chính src/index.ts để nhập create.ts , verify.ts , và rateLimitMiddleWare
import { Hono } from "hono";
import { rateLimitMiddleware } from "./lib/ratelimit";
import create from "./routes/create";
import verify from "./routes/verify";
import type { Env } from "./types/api";
const app = new Hono<{
Bindings: Env;
}>().basePath("/keys");
app.use("*", rateLimitMiddleware);
// add the create file route and verify file route
app.route("/", create);
app.route("/", verify);
export default app;
Bước 6:Triển khai
Triển khai ứng dụng Keyflow của bạn cho Cloudflare Workers:
-
Cài đặt Wrangler:
npm install -g wrangler -
Xác thực bằng Cloudflare:
wrangler login -
Triển khai nhân viên của bạn:
wrangler deploy
Bước 7:Triển khai
Bây giờ chúng ta đã sẵn sàng cho ứng dụng của mình, hãy triển khai nó lên Cloudflare Workers:
-
Đảm bảo bạn đã cài đặt Wrangler CLI:
npm install -g wrangler -
Xác thực bằng tài khoản Cloudflare của bạn:
wrangler login -
Triển khai nhân viên của bạn:
wrangler deploy
Bước 8:Kiểm tra API của bạn
Hãy kiểm tra API mới được triển khai của chúng tôi:
Tạo khóa API mới
curl -X POST https://keyflow.<your-subdomain>.workers.dev/keys/create \
-H "Content-Type: application/json" \
-d '{
"apiId": "my-api",
"prefix": "prod",
"name": "Production API Key",
"expires": 1735689600000,
"meta": {
"environment": "production",
"team": "backend"
}
}'
Xác minh khóa API
curl -X POST https://keyflow.<your-subdomain>.workers.dev/keys/verify \
-H "Content-Type: application/json" \
-d '{
"key": "prod_AbC123XyZ..."
}'
Thay thế <your-subdomain> với tên miền phụ Cloudflare Workers của bạn và prod_AbC123XyZ... bằng một khóa thực tế được tạo từ điểm cuối tạo.
Kết luận
Tạo trình tạo khóa API là một bước quan trọng trong việc bảo mật API của ứng dụng và quản lý những ai có thể truy cập dịch vụ của bạn. Bằng cách xây dựng một hệ thống có thể tạo, xác thực và quản lý khóa API, bạn sẽ thêm một lớp kiểm soát truy cập mạnh mẽ giúp giữ cho dữ liệu của bạn an toàn và có tổ chức.
Dưới đây là tóm tắt nhanh về những gì tạo nên một trình tạo khóa API vững chắc:
- Tạo khóa an toàn :Khóa độc đáo, an toàn bao gồm các tùy chọn như tiền tố tùy chỉnh hoặc độ dài cố định giúp mỗi khóa trở nên khác biệt và khó đoán hơn.
- Xác thực và hết hạn :Việc thêm các bước kiểm tra và ngày hết hạn sẽ đảm bảo mỗi khóa chỉ có hiệu lực trong một khoảng thời gian nhất định, giúp bạn dễ dàng kiểm soát và giới hạn quyền truy cập khi cần.
- Giới hạn siêu dữ liệu và tỷ lệ :Việc lưu trữ thông tin bổ sung với từng khóa và đặt giới hạn tốc độ cho phép bạn giám sát việc sử dụng khóa, theo dõi hoạt động và tránh mọi hành vi lạm dụng API của mình.
Việc sử dụng các công cụ như Upstash Redis và Cloudflare Workers giúp bạn dễ dàng xây dựng một hệ thống quản lý khóa phân tán toàn cầu và không cần máy chủ, có khả năng mở rộng quy mô tốt và hoạt động hiệu quả.
Với nền tảng này, bạn đã sẵn sàng để duy trì quyền truy cập vào các API của mình một cách an toàn và dễ quản lý, giúp bạn yên tâm rằng tài nguyên của mình được bảo vệ và dễ giám sát.