config_editor/login.py
2026-01-19 08:02:47 +00:00

240 lines
8.8 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 json
import os
import datetime
from pathlib import Path
from typing import Tuple, Optional
class SimpleAuth:
"""用户认证管理器"""
def __init__(self, config_path: str = None):
"""
初始化认证管理器
Args:
config_path: 用户配置文件路径
"""
self.config_path = config_path
self.users = {}
# 初始化时加载用户数据
if config_path:
self.load_users()
def load_users(self) -> bool:
"""加载用户数据"""
try:
if not self.config_path:
print("未设置配置文件路径")
return False
# 如果文件不存在,创建空文件
if not os.path.exists(self.config_path):
print(f"配置文件不存在,创建空文件: {self.config_path}")
return self.create_empty_file()
# 读取文件内容
with open(self.config_path, 'r', encoding='utf-8') as f:
content = f.read().strip()
if not content: # 空文件
self.users = {}
return True
# 解析JSON
self.users = json.loads(content)
print(f"已加载 {len(self.users)} 个用户")
return True
except json.JSONDecodeError:
print("配置文件格式错误,重置为空文件")
return self.create_empty_file()
except Exception as e:
print(f"加载用户数据失败: {e}")
return False
def create_empty_file(self) -> bool:
"""创建空的配置文件"""
try:
if not self.config_path:
return False
os.makedirs(os.path.dirname(self.config_path), exist_ok=True)
self.users = {}
with open(self.config_path, 'w', encoding='utf-8') as f:
json.dump({}, f, indent=2, ensure_ascii=False)
print(f"已创建空白配置文件: {self.config_path}")
return True
except Exception as e:
print(f"创建配置文件失败: {e}")
return False
def save_users(self) -> bool:
"""保存用户数据"""
try:
if not self.config_path:
return False
os.makedirs(os.path.dirname(self.config_path), exist_ok=True)
with open(self.config_path, 'w', encoding='utf-8') as f:
json.dump(self.users, f, indent=2, ensure_ascii=False)
return True
except Exception as e:
print(f"保存用户数据失败: {e}")
return False
def authenticate(self, username: str, password: str) -> Tuple[bool, str]:
"""
验证用户凭据
重要:如果用户不存在,则创建用户(首次登录即注册)
"""
if not username or not password:
return False, "用户名和密码不能为空"
# 加载用户数据
if not self.load_users():
return False, "加载用户数据失败"
# 检查用户名是否存在(作为字典键)
if username not in self.users:
# 首次登录,自动创建用户
print(f"用户 '{username}' 不存在,首次登录将自动创建用户")
return self.create_first_user(username, password)
# 检查密码是否正确
user_info = self.users[username]
if user_info.get("password") != password:
return False, "密码错误"
# 更新最后登录时间
user_info["last_login"] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self.save_users()
return True, "登录成功"
def create_first_user(self, username: str, password: str) -> Tuple[bool, str]:
"""创建第一个用户(首次登录)"""
try:
current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
# 创建用户信息
self.users[username] = {
"username": username,
"password": password,
"secondary_password": "", # 二级密码初始为空,首次登录后设置
"created_at": current_time,
"last_login": current_time,
"is_first_user": True
}
# 保存用户数据
if self.save_users():
print(f"已创建用户 '{username}' 并登录")
return True, f"首次登录成功,已创建用户 '{username}'"
else:
return False, "创建用户失败"
except Exception as e:
print(f"创建用户失败: {e}")
return False, f"创建用户失败: {str(e)}"
def set_secondary_password(self, username: str, secondary_password: str) -> Tuple[bool, str]:
"""设置二级密码"""
try:
if not self.load_users():
return False, "加载用户数据失败"
if username not in self.users:
return False, "用户不存在"
if not secondary_password:
return False, "二级密码不能为空"
# 更新二级密码
self.users[username]["secondary_password"] = secondary_password
self.users[username]["secondary_password_updated_at"] = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
if self.save_users():
return True, "二级密码设置成功"
else:
return False, "保存二级密码失败"
except Exception as e:
return False, f"设置二级密码失败: {str(e)}"
def verify_secondary_password(self, username: str, secondary_password: str) -> Tuple[bool, str]:
"""验证二级密码"""
try:
if not self.load_users():
return False, "加载用户数据失败"
if username not in self.users:
return False, "用户不存在"
user_info = self.users[username]
# 检查用户是否设置了二级密码
if not user_info.get("secondary_password"):
return False, "未设置二级密码,请先设置"
# 验证二级密码
if user_info.get("secondary_password") != secondary_password:
return False, "二级密码错误"
return True, "二级密码验证成功"
except Exception as e:
return False, f"验证二级密码失败: {str(e)}"
def get_secondary_password_status(self, username: str) -> Tuple[bool, str]:
"""获取二级密码设置状态"""
try:
if not self.load_users():
return False, "加载用户数据失败"
if username not in self.users:
return False, "用户不存在"
user_info = self.users[username]
if user_info.get("secondary_password"):
return True, f"已设置二级密码(更新于: {user_info.get('secondary_password_updated_at', '未知时间')}"
else:
return False, "未设置二级密码"
except Exception as e:
return False, f"获取二级密码状态失败: {str(e)}"
def get_default_config_path(self) -> str:
"""获取默认配置文件路径"""
return str(Path.home() / ".config_editor" / "users.json")
@staticmethod
def validate_config_path(config_path: str) -> bool:
"""验证配置文件路径是否有效"""
try:
# 检查路径是否包含有效的目录
dir_path = os.path.dirname(config_path)
if not dir_path:
return False
# 检查是否是绝对路径
if not os.path.isabs(config_path):
return False
# 检查文件扩展名(可选)
if not config_path.endswith(('.json', '.txt', '.dat')):
return False
return True
except Exception:
return False