Backend (Django 4.2 + DRF): - Admin auth with SimpleJWT - Volcengine API client with HMAC-SHA256 signing - IAM user management (create/sync/import/disable/enable) - Billing query with pagination - Feishu webhook notifications (async) - APScheduler for periodic spending checks - AES-256 encrypted credential storage - API key auth for external system integration Frontend (Vue 3 + Element Plus): - Login page - Dashboard with stats overview - IAM user list with per-user threshold config - Billing view with spending progress bars - Alert history with type filtering - Settings page for global config and Volcengine account management Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
57 lines
1.3 KiB
Python
57 lines
1.3 KiB
Python
"""AES 加密/解密工具,用于安全存储火山引擎密钥"""
|
|
|
|
import logging
|
|
from cryptography.fernet import Fernet, InvalidToken
|
|
from django.conf import settings
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
_fernet = None
|
|
|
|
|
|
def _get_fernet():
|
|
global _fernet
|
|
if _fernet is not None:
|
|
return _fernet
|
|
|
|
key = settings.AIRGATE_ENCRYPTION_KEY
|
|
if not key:
|
|
logger.warning("AIRGATE_ENCRYPTION_KEY 未设置,密钥将以明文存储!")
|
|
return None
|
|
|
|
try:
|
|
_fernet = Fernet(key.encode() if isinstance(key, str) else key)
|
|
return _fernet
|
|
except Exception as e:
|
|
logger.error(f"加密密钥格式错误: {e}")
|
|
return None
|
|
|
|
|
|
def encrypt(plaintext: str) -> str:
|
|
if not plaintext:
|
|
return ''
|
|
f = _get_fernet()
|
|
if f is None:
|
|
return plaintext
|
|
return f.encrypt(plaintext.encode()).decode()
|
|
|
|
|
|
def decrypt(ciphertext: str) -> str:
|
|
if not ciphertext:
|
|
return ''
|
|
f = _get_fernet()
|
|
if f is None:
|
|
return ciphertext
|
|
try:
|
|
return f.decrypt(ciphertext.encode()).decode()
|
|
except InvalidToken:
|
|
logger.error("解密失败:密文无效或加密密钥已变更")
|
|
return ''
|
|
|
|
|
|
def make_hint(ak: str) -> str:
|
|
"""生成 AK 脱敏提示,如 AKLT****3A"""
|
|
if len(ak) <= 8:
|
|
return '****'
|
|
return f"{ak[:4]}****{ak[-4:]}"
|