EG/plugins/user/realtime_communication/auth/auth_manager.py
2025-12-12 16:16:15 +08:00

900 lines
29 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""
认证管理器模块
确保通信安全
"""
import time
import hashlib
import secrets
import hmac
from typing import Dict, Any, List, Optional
class AuthManager:
"""
认证管理器
确保通信安全
"""
def __init__(self, plugin):
"""
初始化认证管理器
Args:
plugin: 实时通信插件实例
"""
self.plugin = plugin
self.enabled = False
self.initialized = False
# 认证配置
self.auth_config = {
"enable_authentication": True,
"auth_timeout": 30.0,
"enable_token_auth": True,
"enable_password_auth": True,
"token_lifetime": 86400, # 24小时
"enable_session_management": True,
"session_timeout": 3600, # 1小时
"enable_two_factor_auth": False,
"max_login_attempts": 5,
"login_lockout_duration": 900, # 15分钟
"enable_ip_filtering": True,
"enable_audit_logging": True
}
# 认证状态
self.auth_state = {
"active_sessions": 0,
"total_authentications": 0,
"successful_authentications": 0,
"failed_authentications": 0
}
# 认证存储
self.sessions = {}
self.tokens = {}
self.login_attempts = {}
self.blocked_ips = {}
# 认证统计
self.auth_stats = {
"tokens_generated": 0,
"sessions_created": 0,
"sessions_expired": 0,
"users_banned": 0,
"auth_errors": 0
}
# 密钥管理
self.secret_key = self._generate_secret_key()
# 回调函数
self.auth_callbacks = {
"auth_success": [],
"auth_failed": [],
"session_created": [],
"session_expired": [],
"user_banned": [],
"auth_error": []
}
# 时间戳记录
self.last_session_cleanup = 0.0
self.last_auth_event = 0.0
print("✓ 认证管理器已创建")
def initialize(self) -> bool:
"""
初始化认证管理器
Returns:
是否初始化成功
"""
try:
print("正在初始化认证管理器...")
# 生成密钥
self.secret_key = self._generate_secret_key()
self.initialized = True
print("✓ 认证管理器初始化完成")
return True
except Exception as e:
print(f"✗ 认证管理器初始化失败: {e}")
self.auth_stats["auth_errors"] += 1
import traceback
traceback.print_exc()
return False
def _generate_secret_key(self) -> str:
"""
生成密钥
Returns:
生成的密钥
"""
try:
return secrets.token_hex(32)
except Exception as e:
print(f"✗ 密钥生成失败: {e}")
# 使用默认密钥(仅用于开发环境)
return "default_secret_key_for_development_purposes_only"
def enable(self) -> bool:
"""
启用认证管理器
Returns:
是否启用成功
"""
try:
if not self.initialized:
print("✗ 认证管理器未初始化")
return False
self.enabled = True
print("✓ 认证管理器已启用")
return True
except Exception as e:
print(f"✗ 认证管理器启用失败: {e}")
self.auth_stats["auth_errors"] += 1
import traceback
traceback.print_exc()
return False
def disable(self):
"""禁用认证管理器"""
try:
self.enabled = False
# 清理会话和令牌
self.sessions.clear()
self.tokens.clear()
print("✓ 认证管理器已禁用")
except Exception as e:
print(f"✗ 认证管理器禁用失败: {e}")
self.auth_stats["auth_errors"] += 1
import traceback
traceback.print_exc()
def finalize(self):
"""清理认证管理器资源"""
try:
# 禁用认证管理器
if self.enabled:
self.disable()
# 清理回调
self.auth_callbacks.clear()
self.initialized = False
print("✓ 认证管理器资源已清理")
except Exception as e:
print(f"✗ 认证管理器资源清理失败: {e}")
import traceback
traceback.print_exc()
def update(self, dt: float):
"""
更新认证管理器状态
Args:
dt: 时间增量(秒)
"""
try:
if not self.enabled:
return
current_time = time.time()
# 定期清理过期会话
if current_time - self.last_session_cleanup > 300: # 每5分钟清理一次
self._cleanup_expired_sessions(current_time)
self.last_session_cleanup = current_time
# 定期清理登录尝试记录
self._cleanup_login_attempts(current_time)
self.last_auth_event = current_time
except Exception as e:
print(f"✗ 认证管理器更新失败: {e}")
self.auth_stats["auth_errors"] += 1
import traceback
traceback.print_exc()
def _cleanup_expired_sessions(self, current_time: float):
"""清理过期会话"""
try:
expired_sessions = []
for session_id, session_data in self.sessions.items():
if current_time - session_data["login_time"] > self.auth_config["session_timeout"]:
expired_sessions.append(session_id)
for session_id in expired_sessions:
del self.sessions[session_id]
self.auth_state["active_sessions"] -= 1
self.auth_stats["sessions_expired"] += 1
# 触发会话过期回调
self._trigger_auth_callback("session_expired", {
"session_id": session_id,
"timestamp": current_time
})
except Exception as e:
print(f"✗ 过期会话清理失败: {e}")
self.auth_stats["auth_errors"] += 1
def _cleanup_login_attempts(self, current_time: float):
"""清理登录尝试记录"""
try:
expired_attempts = []
for ip_address, attempt_data in self.login_attempts.items():
if current_time - attempt_data["last_attempt"] > self.auth_config["login_lockout_duration"]:
expired_attempts.append(ip_address)
for ip_address in expired_attempts:
del self.login_attempts[ip_address]
except Exception as e:
print(f"✗ 登录尝试记录清理失败: {e}")
self.auth_stats["auth_errors"] += 1
def authenticate_client(self, client_id: str, auth_data: Dict[str, Any]) -> bool:
"""
认证客户端
Args:
client_id: 客户端ID
auth_data: 认证数据
Returns:
是否认证成功
"""
try:
if not self.enabled or not self.auth_config["enable_authentication"]:
# 如果未启用认证,直接通过
return True
# 检查IP是否被阻止
client_ip = auth_data.get("client_ip", "")
if self._is_ip_blocked(client_ip):
self.auth_stats["failed_authentications"] += 1
return False
# 检查登录尝试次数
if self._is_login_blocked(client_ip):
self.auth_stats["failed_authentications"] += 1
return False
# 执行认证
auth_result = self._perform_authentication(client_id, auth_data)
if auth_result:
self.auth_state["successful_authentications"] += 1
self.auth_state["total_authentications"] += 1
# 触发认证成功回调
self._trigger_auth_callback("auth_success", {
"client_id": client_id,
"auth_data": auth_data,
"timestamp": time.time()
})
# 记录审计日志
if self.auth_config["enable_audit_logging"]:
self._log_auth_event("auth_success", client_id, client_ip)
else:
self.auth_state["failed_authentications"] += 1
self.auth_state["total_authentications"] += 1
# 记录失败的登录尝试
self._record_failed_login(client_ip)
# 触发认证失败回调
self._trigger_auth_callback("auth_failed", {
"client_id": client_id,
"auth_data": auth_data,
"timestamp": time.time()
})
# 记录审计日志
if self.auth_config["enable_audit_logging"]:
self._log_auth_event("auth_failed", client_id, client_ip)
return auth_result
except Exception as e:
print(f"✗ 客户端认证失败: {e}")
self.auth_stats["auth_errors"] += 1
return False
def _is_ip_blocked(self, client_ip: str) -> bool:
"""
检查IP是否被阻止
Args:
client_ip: 客户端IP
Returns:
IP是否被阻止
"""
try:
if not self.auth_config["enable_ip_filtering"]:
return False
if client_ip in self.blocked_ips:
block_data = self.blocked_ips[client_ip]
if time.time() - block_data["block_time"] < block_data["duration"]:
return True
else:
# 阻止时间已过期,移除
del self.blocked_ips[client_ip]
return False
except Exception as e:
print(f"✗ IP阻止检查失败: {e}")
self.auth_stats["auth_errors"] += 1
return False
def _is_login_blocked(self, client_ip: str) -> bool:
"""
检查登录是否被阻止
Args:
client_ip: 客户端IP
Returns:
登录是否被阻止
"""
try:
if client_ip in self.login_attempts:
attempts = self.login_attempts[client_ip]
if (attempts["count"] >= self.auth_config["max_login_attempts"] and
time.time() - attempts["last_attempt"] < self.auth_config["login_lockout_duration"]):
return True
return False
except Exception as e:
print(f"✗ 登录阻止检查失败: {e}")
self.auth_stats["auth_errors"] += 1
return False
def _record_failed_login(self, client_ip: str):
"""
记录失败的登录尝试
Args:
client_ip: 客户端IP
"""
try:
current_time = time.time()
if client_ip not in self.login_attempts:
self.login_attempts[client_ip] = {
"count": 1,
"last_attempt": current_time
}
else:
self.login_attempts[client_ip]["count"] += 1
self.login_attempts[client_ip]["last_attempt"] = current_time
# 如果超过最大尝试次数阻止IP
if (self.login_attempts[client_ip]["count"] >=
self.auth_config["max_login_attempts"]):
self._block_ip(client_ip, self.auth_config["login_lockout_duration"])
except Exception as e:
print(f"✗ 失败登录记录失败: {e}")
self.auth_stats["auth_errors"] += 1
def _perform_authentication(self, client_id: str, auth_data: Dict[str, Any]) -> bool:
"""
执行认证
Args:
client_id: 客户端ID
auth_data: 认证数据
Returns:
是否认证成功
"""
try:
# 检查认证类型
auth_type = auth_data.get("auth_type", "token")
if auth_type == "token":
return self._authenticate_with_token(client_id, auth_data)
elif auth_type == "password":
return self._authenticate_with_password(client_id, auth_data)
elif auth_type == "session":
return self._authenticate_with_session(client_id, auth_data)
else:
# 默认认证方式
return self._authenticate_with_token(client_id, auth_data)
except Exception as e:
print(f"✗ 认证执行失败: {e}")
self.auth_stats["auth_errors"] += 1
return False
def _authenticate_with_token(self, client_id: str, auth_data: Dict[str, Any]) -> bool:
"""
使用令牌认证
Args:
client_id: 客户端ID
auth_data: 认证数据
Returns:
是否认证成功
"""
try:
token = auth_data.get("token")
if not token:
return False
# 验证令牌
if token in self.tokens:
token_data = self.tokens[token]
if time.time() - token_data["created_time"] < self.auth_config["token_lifetime"]:
# 令牌有效,创建会话
self._create_session(client_id, auth_data)
return True
else:
# 令牌过期,移除
del self.tokens[token]
return False
except Exception as e:
print(f"✗ 令牌认证失败: {e}")
self.auth_stats["auth_errors"] += 1
return False
def _authenticate_with_password(self, client_id: str, auth_data: Dict[str, Any]) -> bool:
"""
使用密码认证
Args:
client_id: 客户端ID
auth_data: 认证数据
Returns:
是否认证成功
"""
try:
username = auth_data.get("username")
password = auth_data.get("password")
if not username or not password:
return False
# 验证密码(简化实现)
# 在实际应用中,这里应该连接到用户数据库验证用户名和密码
if username == "test_user" and password == "test_password":
# 创建会话
self._create_session(client_id, auth_data)
return True
else:
return False
except Exception as e:
print(f"✗ 密码认证失败: {e}")
self.auth_stats["auth_errors"] += 1
return False
def _authenticate_with_session(self, client_id: str, auth_data: Dict[str, Any]) -> bool:
"""
使用会话认证
Args:
client_id: 客户端ID
auth_data: 认证数据
Returns:
是否认证成功
"""
try:
session_id = auth_data.get("session_id")
if not session_id:
return False
# 检查会话是否存在且有效
if session_id in self.sessions:
session_data = self.sessions[session_id]
if time.time() - session_data["login_time"] < self.auth_config["session_timeout"]:
# 更新会话最后活动时间
session_data["last_activity"] = time.time()
return True
return False
except Exception as e:
print(f"✗ 会话认证失败: {e}")
self.auth_stats["auth_errors"] += 1
return False
def _create_session(self, client_id: str, auth_data: Dict[str, Any]):
"""
创建会话
Args:
client_id: 客户端ID
auth_data: 认证数据
"""
try:
session_id = self._generate_session_id()
session_data = {
"client_id": client_id,
"login_time": time.time(),
"last_activity": time.time(),
"user_id": auth_data.get("user_id", ""),
"username": auth_data.get("username", ""),
"permissions": auth_data.get("permissions", [])
}
self.sessions[session_id] = session_data
self.auth_state["active_sessions"] += 1
self.auth_stats["sessions_created"] += 1
# 触发会话创建回调
self._trigger_auth_callback("session_created", {
"session_id": session_id,
"client_id": client_id,
"auth_data": auth_data,
"timestamp": time.time()
})
except Exception as e:
print(f"✗ 会话创建失败: {e}")
self.auth_stats["auth_errors"] += 1
def _generate_session_id(self) -> str:
"""
生成会话ID
Returns:
生成的会话ID
"""
try:
return secrets.token_urlsafe(32)
except Exception as e:
print(f"✗ 会话ID生成失败: {e}")
self.auth_stats["auth_errors"] += 1
return f"session_{int(time.time() * 1000000)}"
def generate_token(self, user_id: str, permissions: List[str] = None) -> str:
"""
生成令牌
Args:
user_id: 用户ID
permissions: 权限列表
Returns:
生成的令牌
"""
try:
token = secrets.token_urlsafe(64)
self.tokens[token] = {
"user_id": user_id,
"permissions": permissions or [],
"created_time": time.time()
}
self.auth_stats["tokens_generated"] += 1
return token
except Exception as e:
print(f"✗ 令牌生成失败: {e}")
self.auth_stats["auth_errors"] += 1
return ""
def validate_token(self, token: str) -> bool:
"""
验证令牌
Args:
token: 令牌
Returns:
令牌是否有效
"""
try:
if not token:
return False
if token in self.tokens:
token_data = self.tokens[token]
if time.time() - token_data["created_time"] < self.auth_config["token_lifetime"]:
return True
else:
# 令牌过期,移除
del self.tokens[token]
return False
except Exception as e:
print(f"✗ 令牌验证失败: {e}")
self.auth_stats["auth_errors"] += 1
return False
def hash_password(self, password: str, salt: str = None) -> Dict[str, str]:
"""
哈希密码
Args:
password: 密码
salt: 盐值(可选)
Returns:
包含哈希值和盐值的字典
"""
try:
if salt is None:
salt = secrets.token_hex(16)
# 使用PBKDF2哈希密码
password_hash = hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), salt.encode('utf-8'), 100000)
return {
"hash": password_hash.hex(),
"salt": salt
}
except Exception as e:
print(f"✗ 密码哈希失败: {e}")
self.auth_stats["auth_errors"] += 1
return {}
def verify_password(self, password: str, password_hash: str, salt: str) -> bool:
"""
验证密码
Args:
password: 密码
password_hash: 密码哈希值
salt: 盐值
Returns:
密码是否正确
"""
try:
# 重新哈希密码
new_hash = hashlib.pbkdf2_hmac('sha256', password.encode('utf-8'), salt.encode('utf-8'), 100000)
return hmac.compare_digest(new_hash.hex(), password_hash)
except Exception as e:
print(f"✗ 密码验证失败: {e}")
self.auth_stats["auth_errors"] += 1
return False
def _block_ip(self, client_ip: str, duration: float):
"""
阻止IP地址
Args:
client_ip: 客户端IP
duration: 阻止持续时间(秒)
"""
try:
self.blocked_ips[client_ip] = {
"block_time": time.time(),
"duration": duration
}
# 触发用户禁止回调
self._trigger_auth_callback("user_banned", {
"ip_address": client_ip,
"duration": duration,
"timestamp": time.time()
})
# 记录审计日志
if self.auth_config["enable_audit_logging"]:
self._log_auth_event("ip_blocked", None, client_ip)
print(f"✓ IP地址已被阻止: {client_ip} (持续 {duration} 秒)")
except Exception as e:
print(f"✗ IP阻止失败: {e}")
self.auth_stats["auth_errors"] += 1
def unblock_ip(self, client_ip: str) -> bool:
"""
解除IP阻止
Args:
client_ip: 客户端IP
Returns:
是否解除成功
"""
try:
if client_ip in self.blocked_ips:
del self.blocked_ips[client_ip]
print(f"✓ IP地址阻止已解除: {client_ip}")
return True
else:
print(f"✗ IP地址未被阻止: {client_ip}")
return False
except Exception as e:
print(f"✗ IP阻止解除失败: {e}")
self.auth_stats["auth_errors"] += 1
return False
def _log_auth_event(self, event_type: str, client_id: str = None, client_ip: str = None):
"""
记录认证事件
Args:
event_type: 事件类型
client_id: 客户端ID可选
client_ip: 客户端IP可选
"""
try:
if not self.auth_config["enable_audit_logging"]:
return
event = {
"event_type": event_type,
"client_id": client_id,
"client_ip": client_ip,
"timestamp": time.time()
}
# 在实际实现中,这里会将事件记录到日志文件或数据库
print(f"[认证日志] {event_type} - 客户端: {client_id}, IP: {client_ip}")
except Exception as e:
print(f"✗ 认证事件记录失败: {e}")
self.auth_stats["auth_errors"] += 1
def get_active_sessions(self) -> Dict[str, Any]:
"""
获取活跃会话
Returns:
活跃会话字典
"""
try:
return self.sessions.copy()
except Exception as e:
print(f"✗ 获取活跃会话失败: {e}")
self.auth_stats["auth_errors"] += 1
return {}
def get_blocked_ips(self) -> Dict[str, Any]:
"""
获取被阻止的IP地址
Returns:
被阻止的IP地址字典
"""
try:
return self.blocked_ips.copy()
except Exception as e:
print(f"✗ 获取被阻止的IP地址失败: {e}")
self.auth_stats["auth_errors"] += 1
return {}
def get_auth_stats(self) -> Dict[str, Any]:
"""
获取认证统计信息
Returns:
认证统计字典
"""
return {
"state": self.auth_state.copy(),
"stats": self.auth_stats.copy(),
"config": self.auth_config.copy()
}
def reset_stats(self):
"""重置认证统计信息"""
try:
self.auth_stats = {
"tokens_generated": 0,
"sessions_created": 0,
"sessions_expired": 0,
"users_banned": 0,
"auth_errors": 0
}
print("✓ 认证统计信息已重置")
except Exception as e:
print(f"✗ 认证统计信息重置失败: {e}")
def set_auth_config(self, config: Dict[str, Any]) -> bool:
"""
设置认证配置
Args:
config: 认证配置字典
Returns:
是否设置成功
"""
try:
self.auth_config.update(config)
print(f"✓ 认证配置已更新: {self.auth_config}")
return True
except Exception as e:
print(f"✗ 认证配置设置失败: {e}")
return False
def get_auth_config(self) -> Dict[str, Any]:
"""
获取认证配置
Returns:
认证配置字典
"""
return self.auth_config.copy()
def _trigger_auth_callback(self, callback_type: str, data: Dict[str, Any]):
"""
触发认证回调
Args:
callback_type: 回调类型
data: 回调数据
"""
try:
if callback_type in self.auth_callbacks:
for callback in self.auth_callbacks[callback_type]:
try:
callback(data)
except Exception as e:
print(f"✗ 认证回调执行失败: {callback_type} - {e}")
except Exception as e:
print(f"✗ 认证回调触发失败: {e}")
def register_auth_callback(self, callback_type: str, callback: callable):
"""
注册认证回调
Args:
callback_type: 回调类型
callback: 回调函数
"""
try:
if callback_type in self.auth_callbacks:
self.auth_callbacks[callback_type].append(callback)
print(f"✓ 认证回调已注册: {callback_type}")
else:
print(f"✗ 无效的回调类型: {callback_type}")
except Exception as e:
print(f"✗ 认证回调注册失败: {e}")
def unregister_auth_callback(self, callback_type: str, callback: callable):
"""
注销认证回调
Args:
callback_type: 回调类型
callback: 回调函数
"""
try:
if callback_type in self.auth_callbacks:
if callback in self.auth_callbacks[callback_type]:
self.auth_callbacks[callback_type].remove(callback)
print(f"✓ 认证回调已注销: {callback_type}")
else:
print(f"✗ 无效的回调类型: {callback_type}")
except Exception as e:
print(f"✗ 认证回调注销失败: {e}")