Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Redis

สร้างคีย์ API ที่ปลอดภัยด้วย Upstash Redis และ Cloudflare Workers:คำแนะนำทีละขั้นตอน

คีย์ API เปรียบเสมือนกุญแจประตูหน้าของบริการของคุณ ซึ่งช่วยให้ผู้ใช้เข้าไปได้ในขณะที่รักษาความปลอดภัย ในบล็อกนี้ ฉันจะแนะนำคุณเกี่ยวกับการสร้างตัวสร้างคีย์ API ที่เรียบง่ายและปลอดภัยโดยใช้ Upstash Redis เพื่อการจัดเก็บข้อมูลที่รวดเร็วแบบไร้เซิร์ฟเวอร์ และ Cloudflare Workers เพื่อจัดการคำขอที่ Edge ไม่ว่าคุณจะตั้งค่าบริการใหม่หรือเพิ่มคีย์ลงในแอปที่มีอยู่ คุณจะได้เรียนรู้วิธีสร้าง จัดเก็บ และตรวจสอบคีย์ API เพื่อให้ทุกอย่างทำงานได้อย่างราบรื่นและมีประสิทธิภาพ

คีย์ API คืออะไร

คีย์ API คือรหัสเฉพาะที่ระบุและตรวจสอบสิทธิ์ผู้ใช้หรือแอปพลิเคชันที่พยายามเข้าถึง API ของคุณ ให้คิดว่ามันเหมือนกับบัตรผ่านส่วนตัว เมื่อมีคนต้องการใช้บริการของคุณ พวกเขาจะต้องแสดง "รหัส" นี้เพื่อพิสูจน์ว่าได้รับอนุญาต คีย์ API ช่วยให้คุณควบคุมผู้ที่สามารถเข้าถึงทรัพยากรของคุณได้ และมักใช้เพื่อติดตามการใช้งาน บังคับใช้ขีดจำกัด หรือป้องกันการเข้าถึงที่ไม่ได้รับอนุญาต เป็นวิธีที่ตรงไปตรงมาในการจัดการการเข้าถึง API และรักษาข้อมูลของคุณให้ปลอดภัย

สิ่งที่เราจะสร้าง

ในคู่มือนี้ เราจะสร้างตัวสร้างคีย์ API ที่มีฟังก์ชันหลักสองฟังก์ชัน:

  1. การสร้างคีย์ API ใหม่ด้วยการตั้งค่าที่กำหนดเอง
  2. การตรวจสอบความถูกต้องของคีย์ API ในขณะที่ดึงข้อมูลเมตาของพวกเขา

คุณสมบัติที่สำคัญจะรวมถึง:

  • คำนำหน้าคีย์ที่ปรับแต่งได้
  • วันหมดอายุ
  • การจำกัดอัตรา
  • การจัดเก็บข้อมูลเมตา
  • บัตรประจำตัวเจ้าของ

เรามาเห็นภาพระบบคีย์ API ของเรากัน

แผนภาพนี้แสดงการโต้ตอบระหว่างไคลเอนต์, Cloudflare Worker ของเรา และ Upstash Redis สำหรับทั้งการสร้างและการตรวจสอบคีย์ API เมื่อคำนึงถึงภาพรวมนี้แล้ว มาเริ่มสร้างระบบของเรากันดีกว่า

สร้างคีย์ API ที่ปลอดภัยด้วย Upstash Redis และ Cloudflare Workers:คำแนะนำทีละขั้นตอน

ข้อกำหนดเบื้องต้น

หากต้องการติดตาม คุณจะต้องมี:

  • ผู้ปฏิบัติงาน Cloudflare  บัญชี
  • สุดยอด  บัญชี
  • Node.js ติดตั้งอยู่บนเครื่องของคุณ

โครงสร้างโครงการ

โครงการของเราจะมีโครงสร้างดังต่อไปนี้:

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

ขั้นตอนที่ 1:การตั้งค่าโครงการ

เริ่มต้นด้วยการตั้งค่าโปรเจ็กต์ของเราและติดตั้งการขึ้นต่อกันที่จำเป็น

สร้างไดเรกทอรีโครงการใหม่

เปิดเทอร์มินัลของคุณและรันคำสั่งต่อไปนี้:

mkdir keyflow
cd keyflow
npm init -y

ติดตั้งการอ้างอิง

เราจะต้องมีแพ็คเกจบางส่วนสำหรับโครงการของเรา:

npm install hono @upstash/redis @upstash/ratelimit @hono/zod-validator zod wrangler

00 :Upstash Redis ไคลเอ็นต์สำหรับสภาพแวดล้อมแบบไร้เซิร์ฟเวอร์15 :ไลบรารีจำกัดอัตราสำหรับ Upstash Redis22 :ขอมิดเดิลแวร์ตรวจสอบสำหรับ Hono32 :ไลบรารีการตรวจสอบสคีมาแรกของ TypeScript41 :CLI ของ Cloudflare สำหรับการพัฒนาและการปรับใช้ของผู้ปฏิบัติงาน

ตั้งค่า Upstash Redis

  1. ลงชื่อเข้าใช้บัญชี Upstash ของคุณและสร้างฐานข้อมูล Redis ใหม่

สร้างคีย์ API ที่ปลอดภัยด้วย Upstash Redis และ Cloudflare Workers:คำแนะนำทีละขั้นตอน

  1. เมื่อสร้างแล้ว ให้ไปที่ส่วน "REST API"

สร้างคีย์ API ที่ปลอดภัยด้วย Upstash Redis และ Cloudflare Workers:คำแนะนำทีละขั้นตอน

  1. คัดลอก 54  และ 64 ใน 78 ส่วน

กำหนดค่าผู้ปฏิบัติงาน Cloudflare

สร้าง 82  ในรูทโปรเจ็กต์ของคุณโดยมีเนื้อหาดังต่อไปนี้:

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"

แทนที่ 97  และ 108  ด้วยค่าที่คุณคัดลอกมาจาก Upstash

ขั้นตอนที่ 2:การกำหนดประเภท API

เริ่มต้นด้วยการกำหนดอินเทอร์เฟซ TypeScript สำหรับคำขอและการตอบกลับ API ของเรา ประเภทเหล่านี้จะช่วยให้เรารักษาความปลอดภัยของประเภทตลอดการใช้งานของเรา สร้างไฟล์ใหม่ 117 :

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;
};
 

ขั้นตอนที่ 3:การใช้การสร้างคีย์ API

ตอนนี้ เรามาสร้างฟังก์ชันยูทิลิตี้เพื่อสร้างคีย์ API ของเรากันดีกว่า สร้างไฟล์ใหม่ 120 :

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;
}
 

ฟังก์ชันนี้สร้างคีย์ API แบบสุ่มโดยใช้ไบต์สุ่มที่ปลอดภัยด้วยการเข้ารหัส เข้ารหัสใน base64 และทำให้ URL ปลอดภัย

ขั้นตอนที่ 4:การจำกัดอัตราการใช้งาน

สร้างไฟล์ 130 :

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();
}

ขั้นตอนที่ 5:การสร้างเส้นทาง API

มาตั้งค่าไฟล์แอปพลิเคชันหลักของเราและสร้างเส้นทาง API ของเรา ไฟล์นี้ตั้งค่าแอปพลิเคชัน Hono ของเราด้วยสองเส้นทางหลัก: 143  สำหรับการสร้างคีย์ API ใหม่และ 157  สำหรับตรวจสอบคีย์ที่มีอยู่ด้วยไฟล์แยกกันสามไฟล์

1. ใช้งานสร้างเส้นทางคีย์ API

สร้างไฟล์ 167 :

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. ใช้ตรวจสอบเส้นทางคีย์ API

สร้างไฟล์ 179 :

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. ใช้งานไฟล์หลักindex.ts

ใช้ไฟล์หลัก 181 เพื่อนำเข้า 190 , 206 และ 219

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;
 

ขั้นตอนที่ 6:การปรับใช้

ปรับใช้แอปพลิเคชัน Keyflow ของคุณกับ Cloudflare Workers:

  1. ติดตั้งแรงเลอร์:

    npm install -g wrangler
  2. ตรวจสอบสิทธิ์กับ Cloudflare:

    wrangler login
  3. ปรับใช้พนักงานของคุณ:

    wrangler deploy

ขั้นตอนที่ 7:การปรับใช้

ตอนนี้เรามีแอปพลิเคชันของเราพร้อมแล้ว เรามาปรับใช้กับ Cloudflare Workers กันดีกว่า:

  1. ตรวจสอบให้แน่ใจว่าคุณได้ติดตั้ง Wrangler CLI แล้ว:

    npm install -g wrangler
    
  2. ตรวจสอบสิทธิ์กับบัญชี Cloudflare ของคุณ:

    wrangler login
    
  3. ปรับใช้พนักงานของคุณ:

    wrangler deploy
    

ขั้นตอนที่ 8:ทดสอบ API ของคุณ

มาทดสอบ API ที่เพิ่งปรับใช้ใหม่ของเรากัน:

การสร้างคีย์ API ใหม่

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"
 }
 }'

การตรวจสอบคีย์ API

curl -X POST https://keyflow.<your-subdomain>.workers.dev/keys/verify \
 -H "Content-Type: application/json" \
 -d '{
 "key": "prod_AbC123XyZ..."
 }'

แทนที่ 222  ด้วยโดเมนย่อย Cloudflare Workers ของคุณและ 236  ด้วยคีย์จริงที่สร้างจากจุดสิ้นสุดการสร้าง

บทสรุป

การสร้างตัวสร้างคีย์ API เป็นขั้นตอนสำคัญในการรักษาความปลอดภัย API ของแอปพลิเคชันของคุณและการจัดการผู้ที่สามารถเข้าถึงบริการของคุณได้ ด้วยการสร้างระบบที่สามารถสร้าง ตรวจสอบ และจัดการคีย์ API คุณจะเพิ่มการควบคุมการเข้าถึงอีกชั้นที่แข็งแกร่งซึ่งจะช่วยรักษาข้อมูลของคุณให้ปลอดภัยและเป็นระเบียบ

ต่อไปนี้เป็นบทสรุปโดยย่อเกี่ยวกับสิ่งที่รวมอยู่ในตัวสร้างคีย์ API ที่แข็งแกร่ง:

  1. การสร้างคีย์ที่ปลอดภัย :คีย์ที่ปลอดภัยและไม่ซ้ำใครที่มีตัวเลือกต่างๆ เช่น คำนำหน้าที่กำหนดเองหรือชุดความยาว ทำให้แต่ละคีย์แตกต่างกันและคาดเดาได้ยาก
  2. การตรวจสอบและการหมดอายุ :การเพิ่มการตรวจสอบและวันหมดอายุทำให้มั่นใจได้ว่าแต่ละคีย์จะใช้ได้ในช่วงเวลาที่กำหนดเท่านั้น ทำให้ง่ายต่อการควบคุมและจำกัดการเข้าถึงตามความจำเป็น
  3. ขีดจำกัดข้อมูลเมตาและอัตรา :การจัดเก็บข้อมูลเพิ่มเติมกับแต่ละคีย์และขีดจำกัดอัตราการตั้งค่าทำให้คุณสามารถตรวจสอบการใช้งานคีย์ ติดตามกิจกรรม และหลีกเลี่ยงการละเมิด API ของคุณ

การใช้เครื่องมืออย่าง Upstash Redis และ Cloudflare Workers ทำให้การสร้างระบบการจัดการคีย์แบบไร้เซิร์ฟเวอร์และกระจายไปทั่วโลกเป็นเรื่องง่าย ซึ่งปรับขนาดได้ดีและทำงานอย่างมีประสิทธิภาพ

ด้วยรากฐานนี้ คุณพร้อมที่จะรักษาการเข้าถึง API ของคุณให้ปลอดภัยและสามารถจัดการได้ ทำให้คุณอุ่นใจได้ว่าทรัพยากรของคุณจะได้รับการปกป้องและง่ายต่อการตรวจสอบ