feat: 管理面板(登录认证+触发AI分析+统计+CLI改密码)
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
"""管理员认证模块
|
||||
|
||||
密码存储:data/admin.json
|
||||
- password_hash: sha256 哈希
|
||||
- salt: 随机盐
|
||||
"""
|
||||
import hashlib
|
||||
import json
|
||||
import os
|
||||
import secrets
|
||||
import time
|
||||
|
||||
DATA_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), "data")
|
||||
ADMIN_FILE = os.path.join(DATA_DIR, "admin.json")
|
||||
|
||||
# 登录 token 有效期 24 小时
|
||||
TOKEN_TTL = 86400
|
||||
|
||||
# 内存中的活跃 token: {token: expire_ts}
|
||||
_active_tokens: dict[str, float] = {}
|
||||
|
||||
|
||||
def _hash_password(password: str, salt: str) -> str:
|
||||
return hashlib.sha256(f"{salt}:{password}".encode()).hexdigest()
|
||||
|
||||
|
||||
def is_configured() -> bool:
|
||||
return os.path.exists(ADMIN_FILE)
|
||||
|
||||
|
||||
def set_password(password: str) -> None:
|
||||
"""设置或更新管理员密码"""
|
||||
os.makedirs(DATA_DIR, exist_ok=True)
|
||||
salt = secrets.token_hex(16)
|
||||
data = {
|
||||
"password_hash": _hash_password(password, salt),
|
||||
"salt": salt,
|
||||
"updated_at": int(time.time()),
|
||||
}
|
||||
with open(ADMIN_FILE, "w") as f:
|
||||
json.dump(data, f, indent=2)
|
||||
|
||||
|
||||
def verify_password(password: str) -> bool:
|
||||
"""验证密码是否正确"""
|
||||
if not is_configured():
|
||||
return False
|
||||
with open(ADMIN_FILE) as f:
|
||||
data = json.load(f)
|
||||
return _hash_password(password, data["salt"]) == data["password_hash"]
|
||||
|
||||
|
||||
def create_token() -> str:
|
||||
"""创建登录 token"""
|
||||
token = secrets.token_urlsafe(32)
|
||||
_active_tokens[token] = time.time() + TOKEN_TTL
|
||||
return token
|
||||
|
||||
|
||||
def verify_token(token: str) -> bool:
|
||||
"""验证 token 是否有效"""
|
||||
if not token:
|
||||
return False
|
||||
expire = _active_tokens.get(token)
|
||||
if expire is None:
|
||||
return False
|
||||
if time.time() > expire:
|
||||
del _active_tokens[token]
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
def revoke_token(token: str) -> None:
|
||||
"""吊销 token"""
|
||||
_active_tokens.pop(token, None)
|
||||
Reference in New Issue
Block a user