File size: 1,991 Bytes
ae4ceef
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
import { type Request, type Response, type NextFunction } from 'express';
import db from '../lib/db.js';

export interface AuthenticatedRequest extends Request {
  user: {
    userId: string;
    apiKeyId: string;
  };
}

/**
 * 验证外部 API Key (Bearer Token 格式)
 * 支持 Header: Authorization: Bearer sk_...
 */
export const verifyApiKey = (req: Request, res: Response, next: NextFunction) => {
  const authHeader = req.headers.authorization;
  
  if (!authHeader || !authHeader.startsWith('Bearer ')) {
    return res.status(401).json({ 
      error: {
        message: "Missing or invalid API key. Please provide your key in 'Authorization: Bearer sk_...' header.",
        type: "invalid_request_error",
        code: "api_key_missing"
      }
    });
  }

  const apiKey = authHeader.split(' ')[1];
  
  try {
    const keyRecord = db.prepare('SELECT id, user_id, last_used, status FROM api_keys WHERE key_secret = ?').get(apiKey) as any;

    if (!keyRecord) {
      return res.status(401).json({
        error: {
          message: "Incorrect API key provided.",
          type: "authentication_error",
          code: "invalid_api_key"
        }
      });
    }

    if (keyRecord.status === 'inactive') {
      return res.status(401).json({
        error: {
          message: "API key is inactive.",
          type: "authentication_error",
          code: "inactive_api_key"
        }
      });
    }

    // 更新最后使用时间 (异步非阻塞)
    db.prepare('UPDATE api_keys SET last_used = CURRENT_TIMESTAMP WHERE id = ?').run(keyRecord.id);

    // 注入用户信息到请求对象
    (req as any).user = {
      userId: keyRecord.user_id,
      apiKeyId: keyRecord.id
    };

    next();
  } catch (err) {
    console.error('[API Auth] Key validation error:', err);
    res.status(500).json({
      error: {
        message: "Internal server error during authentication.",
        type: "server_error",
        code: "internal_error"
      }
    });
  }
};