Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Redis

Tạo khóa API an toàn với Upstash Redis &Cloudflare Workers:Hướng dẫn từng bước

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:

  1. Tạo khóa API mới bằng cài đặt tùy chỉnh
  2. 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.

Tạo khóa API an toàn với Upstash Redis &Cloudflare Workers:Hướng dẫn từng bước

Đ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

  1. Đă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

Tạo khóa API an toàn với Upstash Redis &Cloudflare Workers:Hướng dẫn từng bước

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

Tạo khóa API an toàn với Upstash Redis &Cloudflare Workers:Hướng dẫn từng bước

  1. Sao chép UPSTASH_REDIS_REST_URL  và UPSTASH_REDIS_REST_TOKEN trong .env phầ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:

  1. Cài đặt Wrangler:

    npm install -g wrangler
  2. Xác thực bằng Cloudflare:

    wrangler login
  3. 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:

  1. Đảm bảo bạn đã cài đặt Wrangler CLI:

    npm install -g wrangler
    
  2. Xác thực bằng tài khoản Cloudflare của bạn:

    wrangler login
    
  3. 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:

  1. 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.
  2. 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.
  3. 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.