api_key_generator.py 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. """
  4. 大模型部署 API Key 生成器
  5. 特性:
  6. - 生成加密安全的随机 API Key
  7. - 支持多种格式(UUID、随机字符串、JWT 风格)
  8. - 包含前缀标识(便于区分用途和环境)
  9. - 支持校验和验证(防止篡改)
  10. - 可配置 Key 长度和复杂度
  11. 使用示例:
  12. # 生成标准 API Key
  13. key = generate_api_key(prefix="sk-prod")
  14. # 生成带有项目标识的 Key
  15. key = generate_api_key(prefix="sk-dev", project_id="proj_123")
  16. # 验证 API Key 格式
  17. is_valid = validate_api_key(key, prefix="sk-prod")
  18. """
  19. import secrets
  20. import hashlib
  21. import base64
  22. import re
  23. import json
  24. import hmac
  25. from datetime import datetime, timedelta
  26. from typing import Optional, Tuple, Dict, Any
  27. from dataclasses import dataclass
  28. from enum import Enum
  29. class KeyFormat(Enum):
  30. """API Key 格式类型"""
  31. STANDARD = "standard" # 标准格式: prefix_xxxxxxxxx
  32. UUID = "uuid" # UUID 格式
  33. JWT_STYLE = "jwt_style" # JWT 风格: xxxxx.yyyyy.zzzzz
  34. BASE64 = "base64" # Base64 编码
  35. HEX = "hex" # 十六进制
  36. @dataclass
  37. class APIKeyConfig:
  38. """API Key 配置"""
  39. prefix: str = "sk" # 前缀,如 sk, pk, dk(secret key, public key, dev key)
  40. environment: str = "prod" # 环境:prod, dev, test
  41. length: int = 32 # 随机部分长度
  42. include_checksum: bool = True # 是否包含校验和
  43. include_timestamp: bool = False # 是否包含时间戳
  44. project_id: Optional[str] = None # 项目标识
  45. secret_key: Optional[str] = None # 用于签名(HMAC)
  46. class APIKeyGenerator:
  47. """API Key 生成器"""
  48. # 推荐的密钥长度(字节)
  49. RECOMMENDED_LENGTHS = {
  50. "low": 16, # 128 bit
  51. "medium": 24, # 192 bit
  52. "high": 32, # 256 bit
  53. "maximum": 48 # 384 bit
  54. }
  55. def __init__(self, config: Optional[APIKeyConfig] = None):
  56. self.config = config or APIKeyConfig()
  57. def generate(self, format_type: KeyFormat = KeyFormat.STANDARD) -> str:
  58. """
  59. 生成 API Key
  60. Args:
  61. format_type: Key 格式类型
  62. Returns:
  63. str: 生成的 API Key
  64. """
  65. generators = {
  66. KeyFormat.STANDARD: self._generate_standard,
  67. KeyFormat.UUID: self._generate_uuid,
  68. KeyFormat.JWT_STYLE: self._generate_jwt_style,
  69. KeyFormat.BASE64: self._generate_base64,
  70. KeyFormat.HEX: self._generate_hex,
  71. }
  72. generator = generators.get(format_type, self._generate_standard)
  73. return generator()
  74. def _generate_standard(self) -> str:
  75. """生成标准格式 API Key: prefix_env_xxxxxxxxx_checksum"""
  76. # 构建前缀
  77. prefix_parts = [self.config.prefix]
  78. if self.config.environment:
  79. prefix_parts.append(self.config.environment)
  80. if self.config.project_id:
  81. prefix_parts.append(self.config.project_id)
  82. prefix = "_".join(prefix_parts)
  83. # 生成随机部分
  84. random_bytes = secrets.token_bytes(self.config.length)
  85. random_part = base64.urlsafe_b64encode(random_bytes).decode('ascii').rstrip('=')
  86. # 可选:添加时间戳
  87. if self.config.include_timestamp:
  88. timestamp = hex(int(datetime.utcnow().timestamp()))[2:]
  89. random_part = f"{timestamp}_{random_part[:24]}"
  90. # 构建基础 key
  91. base_key = f"{prefix}_{random_part[:self.config.length]}"
  92. # 可选:添加校验和
  93. if self.config.include_checksum:
  94. checksum = self._calculate_checksum(base_key)
  95. return f"{base_key}_{checksum}"
  96. return base_key
  97. def _generate_uuid(self) -> str:
  98. """生成 UUID 风格 API Key"""
  99. # 生成 16 字节随机数
  100. random_bytes = secrets.token_bytes(16)
  101. # 转换为 UUID 格式
  102. hex_str = random_bytes.hex()
  103. uuid_format = f"{hex_str[:8]}-{hex_str[8:12]}-{hex_str[12:16]}-{hex_str[16:20]}-{hex_str[20:32]}"
  104. prefix = f"{self.config.prefix}-{self.config.environment}" if self.config.environment else self.config.prefix
  105. return f"{prefix}-{uuid_format}"
  106. def _generate_jwt_style(self) -> str:
  107. """生成 JWT 风格 API Key: header.payload.signature"""
  108. # Header
  109. header = {
  110. "alg": "HS256" if self.config.secret_key else "none",
  111. "typ": "API-KEY",
  112. "env": self.config.environment,
  113. "prefix": self.config.prefix
  114. }
  115. header_b64 = base64.urlsafe_b64encode(
  116. json.dumps(header, separators=(',', ':')).encode()
  117. ).decode().rstrip('=')
  118. # Payload(随机数据 + 时间戳)
  119. payload_data = secrets.token_hex(16)
  120. payload = {
  121. "rnd": payload_data,
  122. "iat": int(datetime.utcnow().timestamp()),
  123. "project": self.config.project_id or "default"
  124. }
  125. payload_b64 = base64.urlsafe_b64encode(
  126. json.dumps(payload, separators=(',', ':')).encode()
  127. ).decode().rstrip('=')
  128. # Signature
  129. if self.config.secret_key:
  130. message = f"{header_b64}.{payload_b64}"
  131. signature = hmac.new(
  132. self.config.secret_key.encode(),
  133. message.encode(),
  134. hashlib.sha256
  135. ).digest()
  136. signature_b64 = base64.urlsafe_b64encode(signature).decode().rstrip('=')[:16]
  137. else:
  138. signature_b64 = secrets.token_urlsafe(16).rstrip('=')
  139. return f"{header_b64}.{payload_b64}.{signature_b64}"
  140. def _generate_base64(self) -> str:
  141. """生成 Base64 编码 API Key"""
  142. random_bytes = secrets.token_bytes(self.config.length)
  143. encoded = base64.urlsafe_b64encode(random_bytes).decode('ascii').rstrip('=')
  144. prefix = f"{self.config.prefix}_{self.config.environment}_" if self.config.environment else f"{self.config.prefix}_"
  145. return f"{prefix}{encoded}"
  146. def _generate_hex(self) -> str:
  147. """生成十六进制 API Key"""
  148. random_bytes = secrets.token_bytes(self.config.length)
  149. hex_str = random_bytes.hex()
  150. prefix = f"{self.config.prefix}_{self.config.environment}_" if self.config.environment else f"{self.prefix}_"
  151. return f"{prefix}{hex_str}"
  152. def _calculate_checksum(self, data: str) -> str:
  153. """计算校验和(前 8 位)"""
  154. hash_obj = hashlib.sha256(data.encode())
  155. return hash_obj.hexdigest()[:8]
  156. @staticmethod
  157. def validate(api_key: str, prefix: Optional[str] = None,
  158. secret_key: Optional[str] = None) -> Tuple[bool, Optional[Dict[str, Any]]]:
  159. """
  160. 验证 API Key 格式
  161. Args:
  162. api_key: 要验证的 API Key
  163. prefix: 期望的前缀(可选)
  164. secret_key: 用于验证签名的密钥(可选)
  165. Returns:
  166. Tuple[bool, Optional[Dict]]: (是否有效, 解析后的信息)
  167. """
  168. if not api_key or len(api_key) < 16:
  169. return False, None
  170. info = {"raw": api_key}
  171. # 检查前缀
  172. if prefix and not api_key.startswith(prefix):
  173. return False, info
  174. # 尝试解析 JWT 风格
  175. if '.' in api_key and api_key.count('.') == 2:
  176. return APIKeyGenerator._validate_jwt_style(api_key, secret_key, info)
  177. # 尝试解析标准格式(检查校验和)
  178. if '_' in api_key:
  179. return APIKeyGenerator._validate_standard(api_key, info)
  180. return True, info
  181. @staticmethod
  182. def _validate_jwt_style(api_key: str, secret_key: Optional[str],
  183. info: Dict) -> Tuple[bool, Dict]:
  184. """验证 JWT 风格 Key"""
  185. parts = api_key.split('.')
  186. if len(parts) != 3:
  187. return False, info
  188. try:
  189. # 解码 header
  190. header_padding = '=' * (4 - len(parts[0]) % 4)
  191. header_json = base64.urlsafe_b64decode(parts[0] + header_padding)
  192. header = json.loads(header_json)
  193. info["header"] = header
  194. # 解码 payload
  195. payload_padding = '=' * (4 - len(parts[1]) % 4)
  196. payload_json = base64.urlsafe_b64decode(parts[1] + payload_padding)
  197. payload = json.loads(payload_json)
  198. info["payload"] = payload
  199. # 验证签名(如果提供了 secret_key)
  200. if secret_key and header.get("alg") == "HS256":
  201. message = f"{parts[0]}.{parts[1]}"
  202. expected_sig = hmac.new(
  203. secret_key.encode(),
  204. message.encode(),
  205. hashlib.sha256
  206. ).digest()
  207. expected_sig_b64 = base64.urlsafe_b64encode(expected_sig).decode().rstrip('=')[:16]
  208. if not hmac.compare_digest(parts[2], expected_sig_b64):
  209. return False, info
  210. return True, info
  211. except Exception:
  212. return False, info
  213. @staticmethod
  214. def _validate_standard(api_key: str, info: Dict) -> Tuple[bool, Dict]:
  215. """验证标准格式 Key(带校验和)"""
  216. parts = api_key.split('_')
  217. # 如果有校验和部分(最后一部分是 8 位十六进制)
  218. if len(parts) >= 2 and len(parts[-1]) == 8 and all(c in '0123456789abcdef' for c in parts[-1]):
  219. # 提取基础 key 和校验和
  220. checksum = parts[-1]
  221. base_key = '_'.join(parts[:-1])
  222. # 验证校验和
  223. expected_checksum = hashlib.sha256(base_key.encode()).hexdigest()[:8]
  224. if checksum != expected_checksum:
  225. return False, info
  226. info["checksum_valid"] = True
  227. info["parts"] = parts[:-1] # 排除校验和部分
  228. else:
  229. info["parts"] = parts
  230. return True, info
  231. # ========== 便捷函数 ==========
  232. def generate_api_key(
  233. prefix: str = "sk",
  234. environment: str = "prod",
  235. length: int = 32,
  236. format_type: KeyFormat = KeyFormat.STANDARD,
  237. include_checksum: bool = True,
  238. project_id: Optional[str] = None,
  239. secret_key: Optional[str] = None
  240. ) -> str:
  241. """
  242. 便捷函数:生成 API Key
  243. Args:
  244. prefix: 前缀(如 sk, pk, dk)
  245. environment: 环境(prod, dev, test)
  246. length: 随机部分长度
  247. format_type: 格式类型
  248. include_checksum: 是否包含校验和
  249. project_id: 项目标识
  250. secret_key: 用于签名的密钥
  251. Returns:
  252. str: 生成的 API Key
  253. Examples:
  254. >>> generate_api_key()
  255. 'sk_prod_xxxxxxxxxxxxxxxx_xxxxxxxx'
  256. >>> generate_api_key(prefix="sk-dev", environment="test")
  257. 'sk-dev_test_xxxxxxxxxxxxxxxx_xxxxxxxx'
  258. >>> generate_api_key(format_type=KeyFormat.UUID)
  259. 'sk-prod-xxxx-xxxx-xxxx-xxxxxxxxxxxx'
  260. """
  261. config = APIKeyConfig(
  262. prefix=prefix,
  263. environment=environment,
  264. length=length,
  265. include_checksum=include_checksum,
  266. project_id=project_id,
  267. secret_key=secret_key
  268. )
  269. generator = APIKeyGenerator(config)
  270. return generator.generate(format_type)
  271. def validate_api_key(
  272. api_key: str,
  273. prefix: Optional[str] = None,
  274. secret_key: Optional[str] = None
  275. ) -> bool:
  276. """
  277. 便捷函数:验证 API Key 格式
  278. Args:
  279. api_key: 要验证的 Key
  280. prefix: 期望的前缀(可选)
  281. secret_key: 用于验证签名的密钥(可选)
  282. Returns:
  283. bool: 是否有效
  284. """
  285. is_valid, _ = APIKeyGenerator.validate(api_key, prefix, secret_key)
  286. return is_valid
  287. def parse_api_key(api_key: str) -> Optional[Dict[str, Any]]:
  288. """
  289. 解析 API Key,提取其中的信息
  290. Args:
  291. api_key: API Key
  292. Returns:
  293. Optional[Dict]: 解析出的信息,无效返回 None
  294. """
  295. is_valid, info = APIKeyGenerator.validate(api_key)
  296. return info if is_valid else None
  297. # ========== 批量生成工具 ==========
  298. def generate_api_keys_batch(
  299. count: int = 10,
  300. prefix: str = "sk",
  301. environment: str = "prod",
  302. format_type: KeyFormat = KeyFormat.STANDARD,
  303. save_to_file: Optional[str] = None
  304. ) -> list:
  305. """
  306. 批量生成 API Key
  307. Args:
  308. count: 生成数量
  309. prefix: 前缀
  310. environment: 环境
  311. format_type: 格式
  312. save_to_file: 保存到文件路径(可选)
  313. Returns:
  314. list: API Key 列表
  315. """
  316. config = APIKeyConfig(prefix=prefix, environment=environment)
  317. generator = APIKeyGenerator(config)
  318. keys = [generator.generate(format_type) for _ in range(count)]
  319. if save_to_file:
  320. with open(save_to_file, 'w', encoding='utf-8') as f:
  321. f.write("# Generated API Keys\n")
  322. f.write(f"# Count: {count}\n")
  323. f.write(f"# Format: {format_type.value}\n")
  324. f.write(f"# Environment: {environment}\n")
  325. f.write("-" * 50 + "\n")
  326. for i, key in enumerate(keys, 1):
  327. f.write(f"{i}. {key}\n")
  328. print(f"Keys saved to: {save_to_file}")
  329. return keys
  330. # ========== 主程序 ==========
  331. if __name__ == "__main__":
  332. print("=" * 60)
  333. print("大模型部署 API Key 生成器")
  334. print("=" * 60)
  335. # 演示各种格式的 API Key
  336. formats = [
  337. ("标准格式", KeyFormat.STANDARD),
  338. ("UUID 格式", KeyFormat.UUID),
  339. ("JWT 风格", KeyFormat.JWT_STYLE),
  340. ("Base64 格式", KeyFormat.BASE64),
  341. ("十六进制格式", KeyFormat.HEX),
  342. ]
  343. print("\n1. 不同格式的 API Key 示例:")
  344. print("-" * 60)
  345. for name, fmt in formats:
  346. key = generate_api_key(format_type=fmt)
  347. print(f"\n{name}:")
  348. print(f" {key}")
  349. # 不同环境的 Key
  350. print("\n\n2. 不同环境的 API Key:")
  351. print("-" * 60)
  352. for env in ["prod", "dev", "test"]:
  353. key = generate_api_key(environment=env)
  354. print(f"\n{env.upper()}:")
  355. print(f" {key}")
  356. # 带校验和的 Key
  357. print("\n\n3. 带校验和的 Key(可验证完整性):")
  358. print("-" * 60)
  359. key_with_checksum = generate_api_key(include_checksum=True)
  360. print(f"\n生成: {key_with_checksum}")
  361. is_valid = validate_api_key(key_with_checksum)
  362. print(f"验证: {'✓ 有效' if is_valid else '✗ 无效'}")
  363. # 验证被篡改的 Key
  364. tampered_key = key_with_checksum[:-8] + "12345678"
  365. print(f"\n篡改: {tampered_key}")
  366. is_valid = validate_api_key(tampered_key)
  367. print(f"验证: {'✓ 有效' if is_valid else '✗ 无效(校验和不匹配)'}")
  368. # 带项目标识的 Key
  369. print("\n\n4. 带项目标识的 Key:")
  370. print("-" * 60)
  371. key_with_project = generate_api_key(
  372. prefix="sk",
  373. environment="prod",
  374. project_id="proj_chatbot"
  375. )
  376. print(f"\n{key_with_project}")
  377. # 批量生成
  378. print("\n\n5. 批量生成(10 个测试 Key):")
  379. print("-" * 60)
  380. test_keys = generate_api_keys_batch(
  381. count=5,
  382. prefix="sk-test",
  383. environment="dev",
  384. format_type=KeyFormat.STANDARD
  385. )
  386. for i, key in enumerate(test_keys, 1):
  387. print(f" {i}. {key}")
  388. # 带签名的 JWT 风格 Key
  389. print("\n\n6. 带 HMAC 签名的 JWT 风格 Key:")
  390. print("-" * 60)
  391. secret = "your-secret-key-here-keep-it-safe"
  392. jwt_key = generate_api_key(
  393. format_type=KeyFormat.JWT_STYLE,
  394. secret_key=secret,
  395. environment="prod",
  396. project_id="llm-api"
  397. )
  398. print(f"\n生成: {jwt_key}")
  399. # 验证签名
  400. is_valid, info = APIKeyGenerator.validate(jwt_key, secret_key=secret)
  401. print(f"签名验证: {'✓ 有效' if is_valid else '✗ 无效'}")
  402. if info and "payload" in info:
  403. print(f"解析信息:")
  404. for k, v in info["payload"].items():
  405. print(f" {k}: {v}")
  406. print("\n" + "=" * 60)
  407. print("使用说明:")
  408. print("=" * 60)
  409. print("""
  410. 建议的生产环境使用方式:
  411. 1. 生成高安全级别的 Key:
  412. key = generate_api_key(
  413. prefix="sk",
  414. environment="prod",
  415. length=32,
  416. include_checksum=True
  417. )
  418. 2. 使用带项目标识的 Key 便于管理:
  419. key = generate_api_key(
  420. prefix="sk",
  421. project_id="your_project_id"
  422. )
  423. 3. 使用 HMAC 签名防止篡改:
  424. key = generate_api_key(
  425. format_type=KeyFormat.JWT_STYLE,
  426. secret_key=your_secret_key
  427. )
  428. 4. 批量生成并保存到文件:
  429. keys = generate_api_keys_batch(
  430. count=100,
  431. save_to_file="api_keys.txt"
  432. )
  433. 安全建议:
  434. - 在生产环境使用 32 字节(256 bit)以上的密钥长度
  435. - 妥善保管 secret_key,不要硬编码在代码中
  436. - 定期轮换 API Key
  437. - 使用环境变量或密钥管理系统存储敏感信息
  438. """)