Files
auv/backend/services/admin_auth.py
T

76 lines
1.8 KiB
Python

"""管理员认证模块
密码存储: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)