Spaces:
Runtime error
Runtime error
File size: 5,812 Bytes
b30d305 | 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 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 | """
认证和授权管理
"""
import hashlib
import secrets
import os
from typing import Optional
from datetime import datetime, timedelta
from src.utils.database import db_manager
from src.utils.logger import setup_logger
from src.utils.env_config import env_config
logger = setup_logger("auth")
class AuthManager:
"""认证管理器"""
def __init__(self):
# 固定会话超时时间为1天
self.session_timeout = timedelta(days=1)
self._ensure_admin_password()
def _ensure_admin_password(self):
"""确保管理员密码已设置"""
stored_password = db_manager.get_config("admin_password_hash")
if not stored_password:
# 如果数据库中没有设置密码,使用环境配置中的默认密码
default_password = env_config.admin_password
self.set_admin_password(default_password)
password_prefix = default_password[:3] + "***" if len(default_password) >= 3 else "***"
logger.info(f"Admin password initialized from environment config (prefix: {password_prefix})")
else:
logger.info("Using existing admin password from database")
def hash_password(self, password: str) -> str:
"""对密码进行哈希"""
# 使用随机盐值
salt = secrets.token_hex(32)
password_hash = hashlib.pbkdf2_hmac('sha256', password.encode(), salt.encode(), 100000)
return f"{salt}:{password_hash.hex()}"
def verify_password(self, password: str, password_hash: str) -> bool:
"""验证密码"""
try:
salt, stored_hash = password_hash.split(':')
password_hash_check = hashlib.pbkdf2_hmac('sha256', password.encode(), salt.encode(), 100000)
return stored_hash == password_hash_check.hex()
except Exception:
return False
def set_admin_password(self, password: str):
"""设置管理员密码"""
password_hash = self.hash_password(password)
db_manager.set_config("admin_password_hash", password_hash)
logger.info("Admin password updated")
def verify_admin_password(self, password: str) -> bool:
"""验证管理员密码"""
stored_hash = db_manager.get_config("admin_password_hash")
if not stored_hash:
return False
return self.verify_password(password, stored_hash)
def generate_session_token(self) -> str:
"""生成会话令牌"""
return secrets.token_urlsafe(32)
def create_session(self, password: str) -> Optional[str]:
"""创建会话"""
if not self.verify_admin_password(password):
return None
session_token = self.generate_session_token()
expires_at = (datetime.now() + self.session_timeout).isoformat()
# 存储会话信息
db_manager.set_config(f"session:{session_token}", expires_at)
logger.info("New admin session created")
return session_token
def verify_session(self, session_token: str) -> bool:
"""验证会话"""
if not session_token:
return False
expires_at_str = db_manager.get_config(f"session:{session_token}")
if not expires_at_str:
return False
try:
expires_at = datetime.fromisoformat(expires_at_str)
if datetime.now() > expires_at:
# 会话已过期,删除
self.delete_session(session_token)
return False
return True
except Exception:
return False
def delete_session(self, session_token: str):
"""删除会话"""
if not session_token:
return
session_key = f"session:{session_token}"
deleted = db_manager.delete_config(session_key)
from src.utils.security import mask_api_key
if deleted:
logger.info(f"Session {mask_api_key(session_token)} deleted successfully")
else:
logger.warning(f"Failed to delete session {mask_api_key(session_token)} - not found")
def cleanup_expired_sessions(self):
"""清理过期会话"""
try:
# 获取所有session配置
session_configs = db_manager.get_configs_by_prefix("session:")
current_time = datetime.now()
cleaned_count = 0
for config in session_configs:
session_key = config["key"]
expires_at_str = config["value"]
try:
expires_at = datetime.fromisoformat(expires_at_str)
if current_time > expires_at:
# 会话已过期,删除
if db_manager.delete_config(session_key):
cleaned_count += 1
session_token = session_key.replace("session:", "")
from src.utils.security import mask_api_key
logger.debug(f"Cleaned expired session: {mask_api_key(session_token)}")
except Exception as e:
# 无效的时间格式,删除这个配置
logger.warning(f"Invalid session expiry format for {session_key}: {e}")
if db_manager.delete_config(session_key):
cleaned_count += 1
logger.info(f"Session cleanup completed. Removed {cleaned_count} expired sessions")
return cleaned_count
except Exception as e:
logger.error(f"Session cleanup failed: {e}")
return 0
# 全局认证管理器实例
auth_manager = AuthManager()
|