ในยุคที่ AI API กลายเป็นโครงสร้างพื้นฐานสำคัญของแอปพลิเคชันสมัยใหม่ การควบคุมการเข้าถึง (Access Control) และการจัดการสิทธิ์อย่างเป็นระบบจึงมีความจำเป็นมากขึ้น โดยเฉพาะเมื่อต้องให้บริการ AI หลายรุ่นพร้อมกัน ในบทความนี้ผมจะพาทุกท่านไปเรียนรู้การออกแบบ RBAC (Role-Based Access Control) สำหรับ AI Gateway ตั้งแต่พื้นฐานจนถึงการนำไปใช้จริง
ทำไมต้องมี Access Control สำหรับ AI API
จากประสบการณ์การสร้างระบบ AI Gateway หลายตัว ผมพบว่าปัญหาหลักที่พบบ่อยคือการจัดการ API Key ที่ไม่ดี และขาดการควบคุมว่าใครสามารถใช้โมเดลใดได้บ้าง ซึ่งส่งผลให้เกิดทั้งปัญหาด้านความปลอดภัยและการควบคุมค่าใช้จ่าย
HolySheep AI สมัครที่นี่ เป็นบริการที่รวม AI API หลายผู้ให้บริการไว้ในที่เดียว รองรับการจ่ายเงินผ่าน WeChat และ Alipay พร้อมอัตราแลกเปลี่ยนที่คุ้มค่า ¥1=$1 ช่วยประหยัดค่าใช้จ่ายได้มากกว่า 85% เมื่อเทียบกับการใช้งาน API อย่างเป็นทางการโดยตรง และมีความหน่วงต่ำมากเพียง <50ms พร้อมเครดิตฟรีเมื่อลงทะเบียน
ตารางเปรียบเทียบบริการ AI Gateway
| เกณฑ์ | HolySheep AI | API อย่างเป็นทางการ | บริการ Relay ทั่วไป |
|---|---|---|---|
| ราคา GPT-4.1 | $8/MTok | $60/MTok | $15-25/MTok |
| ราคา Claude Sonnet 4.5 | $15/MTok | $45/MTok | $20-35/MTok |
| ราคา Gemini 2.5 Flash | $2.50/MTok | $7.50/MTok | $4-6/MTok |
| ราคา DeepSeek V3.2 | $0.42/MTok | ไม่มีโดยตรง | $0.80-1.50/MTok |
| การชำระเงิน | WeChat/Alipay, USD | บัตรเครดิตเท่านั้น | บัตรเครดิต/USD |
| ความหน่วง (Latency) | <50ms | 80-150ms | 100-200ms |
| RBAC Built-in | มี | ไม่มี (ต้องซื้อ separate) | ขึ้นอยู่กับผู้ให้บริการ |
RBAC Permission Model คืออะไร
RBAC หรือ Role-Based Access Control เป็นวิธีการจัดการสิทธิ์การเข้าถึงที่กำหนดสิทธิ์ตามบทบาท (Role) ของผู้ใช้ แทนที่จะกำหนดสิทธิ์ให้แต่ละคนโดยตรง ซึ่งทำให้การจัดการง่ายขึ้นและสอดคล้องกับหลักการ Principle of Least Privilege
โครงสร้างข้อมูลสำหรับ RBAC
// โครงสร้างข้อมูลพื้นฐานสำหรับ RBAC Model
// 1. Permission - สิทธิ์การเข้าถึง
interface Permission {
id: string;
name: string; // เช่น "chat:gpt-4", "admin:users"
resource: string; // ทรัพยากรที่เข้าถึง เช่น "chat", "admin"
action: string; // การกระทำ เช่น "read", "write", "delete"
model?: string; // รุ่น AI ที่อนุญาต (ถ้ามี)
}
// 2. Role - บทบาท
interface Role {
id: string;
name: string; // เช่น "developer", "admin", "viewer"
permissions: string[]; // รายการ Permission IDs
rateLimit: {
requestsPerMinute: number;
tokensPerDay: number;
};
}
// 3. User - ผู้ใช้
interface User {
id: string;
email: string;
roles: string[]; // รายการ Role IDs
apiKey: string;
isActive: boolean;
createdAt: Date;
}
// 4. API Key Metadata
interface APIKeyMetadata {
keyId: string; // รหัสที่สั้นกว่า key เต็ม
userId: string;
permissions: string[];
rateLimit: RateLimitConfig;
expiresAt?: Date;
}
การสร้างระบบ RBAC สำหรับ AI Gateway
ในการพัฒนาระบบ AI Gateway ที่มีความปลอดภัยและจัดการได้ง่าย ผมแนะนำให้แบ่งการออกแบบออกเป็น 3 ชั้นหลัก ดังนี้
ชั้นที่ 1: Authentication Layer
// middleware/auth.ts - Authentication Middleware
import { Request, Response, NextFunction } from 'express';
interface AuthConfig {
apiKeyHeader: string;
keyPrefix: string;
}
// ตั้งค่าสำหรับ HolySheep AI API
const authConfig: AuthConfig = {
apiKeyHeader: 'x-api-key',
keyPrefix: 'hs_'
};
interface TokenPayload {
userId: string;
keyId: string;
permissions: string[];
rateLimit: {
requestsPerMinute: number;
tokensPerDay: number;
};
}
async function authenticateAPIKey(
req: Request,
res: Response,
next: NextFunction
): Promise {
const apiKey = req.headers[authConfig.apiKeyHeader] as string;
if (!apiKey) {
res.status(401).json({
error: 'missing_api_key',
message: 'API key is required'
});
return;
}
if (!apiKey.startsWith(authConfig.keyPrefix)) {
res.status(401).json({
error: 'invalid_api_key_format',
message: 'Invalid API key format'
});
return;
}
try {
// ตรวจสอบ API key กับฐานข้อมูล
const payload = await verifyAndDecodeKey(apiKey);
if (!payload) {
res.status(401).json({
error: 'invalid_api_key',
message: 'API key is invalid or expired'
});
return;
}
// เก็บข้อมูลผู้ใช้ไว้ใน request
(req as any).auth = payload;
next();
} catch (error) {
res.status(500).json({
error: 'authentication_error',
message: 'Failed to authenticate'
});
}
}
// ฟังก์ชันตรวจสอบ API key
async function verifyAndDecodeKey(apiKey: string): Promise<TokenPayload | null> {
// ในการใช้งานจริง ให้ตรวจสอบกับฐานข้อมูล
// ตัวอย่างนี้ใช้ HolySheep AI
const response = await fetch('https://api.holysheep.ai/v1/auth/verify', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': Bearer ${apiKey}
}
});
if (!response.ok) return null;
return response.json();
}
export { authenticateAPIKey, authConfig };
ชั้นที่ 2: Authorization Layer
// middleware/authorize.ts - Authorization Middleware
interface Permission {
resource: string;
action: string;
model?: string;
}
interface AuthPayload {
userId: string;
permissions: string[];
rateLimit: RateLimitConfig;
}
// สร้าง middleware สำหรับตรวจสอบสิทธิ์
function requirePermission(permission: Permission) {
return async (req: Request, res: Response, next: NextFunction): Promise<void> => {
const auth = (req as any).auth as AuthPayload;
if (!auth) {
res.status(401).json({
error: 'not_authenticated',
message: 'Authentication required'
});
return;
}
// ตรวจสอบว่ามีสิทธิ์ที่ต้องการหรือไม่
const hasPermission = checkPermission(auth.permissions, permission);
if (!hasPermission) {
res.status(403).json({
error: 'permission_denied',
message: Permission denied: ${permission.resource}:${permission.action},
required: permission
});
return;
}
next();
};
}
// ตรวจสอบสิทธิ์
function checkPermission(userPermissions: string[], required: Permission): boolean {
const permissionString = required.model
? ${required.resource}:${required.action}:${required.model}
: ${required.resource}:${required.action};
// ตรวจสอบ permission ที่ตรงกัน
if (userPermissions.includes(permissionString)) {
return true;
}
// ตรวจสอบ wildcard permission
// เช่น "chat:*" หมายถึงทำได้ทุก action
const wildcardPermission = required.model
? ${required.resource}:*:${required.model}
: ${required.resource}:*;
if (userPermissions.includes(wildcardPermission)) {
return true;
}
// ตรวจสอบ admin permission
if (userPermissions.includes('admin:*')) {
return true;
}
return false;
}
// Pre-defined permission middleware
const chatPermissions = {
gpt4: requirePermission({ resource: 'chat', action: 'create', model: 'gpt-4' }),
gpt35: requirePermission({ resource: 'chat', action: 'create', model: 'gpt-3.5-turbo' }),
claude: requirePermission({ resource: 'chat', action: 'create', model: 'claude-3-sonnet' }),
gemini: requirePermission({ resource: 'chat', action: 'create', model: 'gemini-pro' }),
deepseek: requirePermission({ resource: 'chat', action: 'create', model: 'deepseek-v3' }),
// สิทธิ์ในการอ่าน
readModels: requirePermission({ resource: 'models', action: 'read' }),
// สิทธิ์ในการจัดการ API keys
manageKeys: requirePermission({ resource: 'apikeys', action: 'write' })
};
export { requirePermission, checkPermission, chatPermissions };
ชั้นที่ 3: Rate Limiting Layer
// middleware/rateLimit.ts - Rate Limiting with Token Bucket
import { Request, Response } from 'express';
// In-memory store (ในการใช้งานจริงควรใช้ Redis)
const rateLimitStore = new Map<string, {
tokens: number;
lastRefill: number;
}>();
interface RateLimitConfig {
requestsPerMinute: number;
tokensPerDay: number;
}
// Token Bucket Algorithm
class TokenBucket {
private tokens: number;
private maxTokens: number;
private refillRate: number; // tokens per second
private lastRefill: number;
constructor(maxTokens: number, refillRate: number) {
this.maxTokens = maxTokens;
this.refillRate = refillRate;
this.tokens = maxTokens;
this.lastRefill = Date.now();
}
consume(tokens: number = 1): boolean {
this.refill();
if (this.tokens >= tokens) {
this.tokens -= tokens;
return true;
}
return false;
}
private refill(): void {
const now = Date.now();
const secondsPassed = (now - this.lastRefill) / 1000;
const tokensToAdd = secondsPassed * this.refillRate;
this.tokens = Math.min(this.maxTokens, this.tokens + tokensToAdd);
this.lastRefill = now;
}
getRemainingTokens(): number {
this.refill();
return Math.floor(this.tokens);
}
}
// สร้าง rate limiter middleware
function createRateLimiter(config: RateLimitConfig) {
const buckets = new Map<string, TokenBucket>();
return async (req: Request, res: Response, next: NextFunction): Promise<void> => {
const auth = (req as any).auth;
if (!auth) {
next();
return;
}
const userId = auth.userId;
const keyId = auth.keyId;
const bucketKey = ${userId}:${keyId};
// สร้าง bucket ถ้ายังไม่มี
if (!buckets.has(bucketKey)) {
buckets.set(bucketKey, new TokenBucket(
config.requestsPerMinute,
config.requestsPerMinute / 60 // refill rate per second
));
}
const bucket = buckets.get(bucketKey)!;
if (!bucket.consume(1)) {
res.status(429).json({
error: 'rate_limit_exceeded',
message: 'Too many requests. Please try again later.',
retryAfter: Math.ceil((1 / bucket.getRemainingTokens()) * 60)
});
return;
}
// เพิ่ม headers สำหรับ client
res.setHeader('X-RateLimit-Limit', config.requestsPerMinute);
res.setHeader('X-RateLimit-Remaining', bucket.getRemainingTokens());
next();
};
}
// Rate limiter สำหรับ token usage
async function checkTokenLimit(
userId: string,
tokenCost: number,
dailyLimit: number
): Promise<boolean> {
// ดึงข้อมูลการใช้งานวันนี้
const today = new Date().toISOString().split('T')[0];
const usageKey = usage:${userId}:${today};
// ในการใช้งานจริงควรใช้ Redis
const currentUsage = parseInt(rateLimitStore.get(usageKey) as any || '0');
if (currentUsage + tokenCost > dailyLimit) {
return false;
}
return true;
}
export { createRateLimiter, checkTokenLimit, TokenBucket };
การใช้งานร่วมกับ HolySheep AI API
เมื่อเรามีระบบ RBAC แล้ว ต่อไปจะเป็นการนำไปใช้งานจริงกับ HolySheep AI API ซึ่งมีความหน่วงต่ำมากและราคาประหยัดกว่ามาก
// services/aiProxy.ts - AI Proxy Service กับ HolySheep
interface ChatRequest {
model: string;
messages: Array<{
role: 'system' | 'user' | 'assistant';
content: string;
}>;
temperature?: number;
maxTokens?: number;
}
interface ProxyConfig {
baseUrl: string;
apiKey: string;
timeout: number;
}
class AIProxyService {
private config: ProxyConfig;
constructor(config: ProxyConfig) {
this.config = config;
}
async chat(request: ChatRequest): Promise<any> {
const { model, messages, temperature = 0.7, maxTokens = 1000 } = request;
// ตรวจสอบ model ที่อนุญาต
const allowedModels = [
'gpt-4', 'gpt-4-turbo', 'gpt-3.5-turbo',
'claude-3-sonnet', 'claude-3-opus', 'claude-3-haiku',
'gemini-pro', 'gemini-flash',
'deepseek-v3', 'deepseek-coder'
];
if (!allowedModels.includes(model)) {
throw new Error(Model '${model}' is not supported);
}
const response = await fetch(${this.config.baseUrl}/chat/completions, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': Bearer ${this.config.apiKey},
'x-model-name': model
},
body: JSON.stringify({
model: model,
messages: messages,
temperature: temperature,
max_tokens: maxTokens
}),
signal: AbortSignal.timeout(this.config.timeout)
});
if (!response.ok) {
const error = await response.json();
throw new Error(error.message || 'API request failed');
}
return response.json();
}
// ตัวอย่างการใช้งาน
async example() {
const service = new AIProxyService({
baseUrl: 'https://api.holysheep.ai/v1',
apiKey: process.env.HOLYSHEEP_API_KEY!,
timeout: 30000
});
// ส่งคำขอไปยัง DeepSeek ซึ่งมีราคาถูกที่สุด
const result = await service.chat({
model: 'deepseek-v3',
messages: [
{ role: 'system', content: 'คุณเป็นผู้ช่วยที่เป็นมิตร' },
{ role: 'user', content: 'อธิบายเกี่ยวกับ RBAC' }
],
temperature: 0.7,
maxTokens: 500
});
console.log('Response:', result.choices[0].message.content);
console.log('Usage:', result.usage);
// { prompt_tokens: 50, completion_tokens: 150, total_tokens: 200 }
}
}
export { AIProxyService, ChatRequest, ProxyConfig };
การสร้าง API Key Management
// services/apiKeyManager.ts - API Key Management System
import crypto from 'crypto';
interface CreateKeyRequest {
userId: string;
name: string;
permissions: string[];
rateLimit: {
requestsPerMinute: number;
tokensPerDay: number;
};
expiresAt?: Date;
}
interface APIKey {
id: string;
keyHash: string;
keyPrefix: string; // สำหรับแสดงให้ผู้ใช้เห็น
userId: string;
name: string;
permissions: string[];
rateLimit: {
requestsPerMinute: number;
tokensPerDay: number;
};
createdAt: Date;
expiresAt?: Date;
isActive: boolean;
lastUsedAt?: Date;
}
class APIKeyManager {
// สร้าง API Key ใหม่
static generateKey(): { key: string; keyId: string; keyHash: string } {
const randomBytes = crypto.randomBytes(32);
const key = hs_${randomBytes.toString('hex')};
const keyHash = crypto.createHash('sha256').update(key).digest('hex');
const keyId = key_${crypto.randomBytes(8).toString('hex')};
return { key, keyId, keyHash };
}
// บันทึก API Key
static async create(request: CreateKeyRequest): Promise<{ key: string; apiKey: APIKey }> {
const { key, keyId, keyHash } = this.generateKey();
const apiKey: APIKey = {
id: keyId,
keyHash,
keyPrefix: key.substring(0, 12) + '...',
userId: request.userId,
name: request.name,
permissions: request.permissions,
rateLimit: request.rateLimit,
createdAt: new Date(),
expiresAt: request.expiresAt,
isActive: true
};
// บันทึกลงฐานข้อมูล
await db.apiKeys.create(apiKey);
// ส่ง key เต็มกลับไปให้ผู้ใช้ครั้งเดียวเท่านั้น
return { key, apiKey };
}
// ตรวจสอบ API Key
static async verify(key: string): Promise<APIKey | null> {
const keyHash = crypto.createHash('sha256').update(key).digest('hex');
const apiKey = await db.apiKeys.findOne({
keyHash,
isActive: true
});
if (!apiKey) return null;
// ตรวจสอบว่าหมดอายุหรือไม่
if (apiKey.expiresAt && new Date() > apiKey.expiresAt) {
return null;
}
// อัปเดต lastUsedAt
await db.apiKeys.update(apiKey.id, {
lastUsedAt: new Date()
});
return apiKey;
}
// ยกเลิก API Key
static async revoke(keyId: string): Promise<boolean> {
const result = await db.apiKeys.update(keyId, {
isActive: false
});
return result.modifiedCount > 0;
}
// ดึงรายการ API Keys ของผู้ใช้
static async listByUser(userId: string): Promise<APIKey[]> {
return db.apiKeys.find({
userId,
isActive: true
});
}
}
// ตัวอย่างการใช้งาน
async function example() {
// สร้าง API Key สำหรับนักพัฒนา
const developer = await APIKeyManager.create({
userId: 'user_123',
name: 'Developer Key',
permissions: [
'chat:create:gpt-3.5-turbo',
'chat:create:deepseek-v3',
'models:read'
],
rateLimit: {
requestsPerMinute: 60,
tokensPerDay: 100000
}
});
console.log('New API Key:', developer.key);
// แสดงให้ผู้ใช้เห็นครั้งเดียว
// hs_a1b2c3d4e5f6...
// ตรวจสอบ API Key
const verified = await APIKeyManager.verify(developer.key);
if (verified) {
console.log('Valid key for:', verified.userId);
console.log('Permissions:', verified.permissions);
}
}
export { APIKeyManager, APIKey, CreateKeyRequest };
ตัวอย่าง Route ที่สมบูรณ์
// routes/ai.ts - AI Routes พร้อม RBAC
import express from 'express';
import { authenticateAPIKey } from '../middleware/auth';
import { chatPermissions, requirePermission } from '../middleware/authorize';
import { createRateLimiter } from '../middleware/rateLimit';
import { AIProxyService } from '../services/aiProxy';
const router = express.Router();
const aiService = new AIProxyService({
baseUrl: 'https://api.holysheep.ai/v1',
apiKey: process.env.HOLYSHEEP_API_KEY!,
timeout: 30000
});
// Middleware สำหรับทุกเส้นทาง
router.use(authenticateAPIKey);
// Route สำหรับ Chat Completion
router.post('/chat/completions',
// ตรวจสอบสิทธิ์ตาม model
async (req: Request, res: Response, next: NextFunction) => {
const model = req.body.model;
// เลือก middleware ที่เหมาะสม
const permissionMiddleware = getPermissionMiddleware(model);
permissionMiddleware(req, res, next);
},
// Rate limiting
createRateLimiter({
requestsPerMinute: 60,
tokensPerDay: 100000
}),
// Handler
async (req: Request, res: Response) => {
try {
const result = await aiService.chat(req.body);
res.json(result);
} catch (error) {
res.status(500).json({
error: 'api_error',
message: error.message
});
}
}
);
// Route สำหรับดูรายการ Models
router.get('/models',
chatPermissions.readModels,
async (req: Request, res: Response) => {
const models = [
{ id: 'gpt-4', name: 'GPT-4', provider: 'OpenAI', price: 8 },
{ id: 'gpt-3.5-turbo', name: 'GPT-3.5 Turbo', provider: 'OpenAI', price: 2 },
{ id: 'claude-3-sonnet', name: 'Claude 3 Sonnet', provider: 'Anthropic', price: 15 },
{ id: 'deepseek-v3', name: 'DeepSeek V3', provider: 'DeepSeek', price: 0.42 },
{ id: 'gemini-pro', name: 'Gemini Pro', provider: 'Google', price: 2.50 }
];
res.json({ models });
}
);
// Route สำหรับดู Usage
router.get('/usage',
requirePermission({ resource: 'usage', action: 'read' }),
async (req: Request, res: Response) => {
const auth = (req as any).auth;
// ดึงข้อมูลการใช้งาน
const usage = await getUserUsage(auth.userId);
res.json({
today: {
tokens: usage.todayTokens,
requests: usage.todayRequests
},
limits: auth.rateLimit
});
}
);
// ฟังก์ชันเลือก middleware ตาม model
function getPermissionMiddleware(model: string) {
switch (model) {
case 'gpt-4':
case 'gpt-4-turbo':
return chatPermissions.gpt4;
case 'gpt-3.5-turbo':
return chatPermissions.gpt35;
case '