mirror of
https://github.com/fawney19/Aether.git
synced 2026-09-02 17:30:23 +08:00
feat: 添加 OAuth 认证支持及相关改进
- 新增 OAuth 模块,支持 LinuxDo/GitHub/Google 等第三方登录 - 用户邮箱改为可选字段,支持无邮箱注册 - 新增模块配置验证状态 (config_validated/config_error) - 系统设置界面改为分块独立保存 - 用户设置新增 OAuth 绑定管理和首次密码设置 - 登录界面支持 OAuth 按钮展示 - 邮箱验证设置移至邮件设置页面
This commit is contained in:
@@ -6,10 +6,11 @@
|
||||
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum
|
||||
from typing import TYPE_CHECKING, Any, Awaitable, Callable, List, Optional
|
||||
from typing import TYPE_CHECKING, Any, Awaitable, Callable, List, Optional, Tuple
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from fastapi import APIRouter
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
|
||||
class ModuleCategory(str, Enum):
|
||||
@@ -84,6 +85,9 @@ class ModuleDefinition:
|
||||
# 自定义依赖检测(可选,用于检测 ldap3 等库是否安装)
|
||||
check_dependencies: Optional[Callable[[], bool]] = None
|
||||
|
||||
# 配置验证(可选,启用模块时调用,返回 (success, error_message))
|
||||
validate_config: Optional[Callable[["Session"], Tuple[bool, str]]] = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class ModuleStatus:
|
||||
@@ -97,6 +101,8 @@ class ModuleStatus:
|
||||
available: bool # 部署级可用(环境变量 + 依赖库)
|
||||
enabled: bool # 运行级启用(数据库配置)
|
||||
active: bool # 最终激活状态 (available && enabled && dependencies_ok)
|
||||
config_validated: bool # 配置验证通过(只有验证通过才允许启用)
|
||||
config_error: Optional[str] # 配置验证失败的错误信息
|
||||
|
||||
# 显示信息
|
||||
display_name: str
|
||||
|
||||
@@ -175,6 +175,34 @@ class ModuleRegistry:
|
||||
|
||||
return True
|
||||
|
||||
# ========== 配置验证 ==========
|
||||
|
||||
def validate_config(self, name: str, db: "Session") -> tuple[bool, str]:
|
||||
"""
|
||||
验证模块配置是否有效
|
||||
|
||||
Args:
|
||||
name: 模块名称
|
||||
db: 数据库会话
|
||||
|
||||
Returns:
|
||||
(validated, error_message) - validated 为 True 表示配置有效
|
||||
"""
|
||||
if name not in self._modules:
|
||||
return False, "模块不存在"
|
||||
|
||||
module = self._modules[name]
|
||||
|
||||
# 没有配置验证函数的模块,默认配置有效
|
||||
if not module.validate_config:
|
||||
return True, ""
|
||||
|
||||
try:
|
||||
return module.validate_config(db)
|
||||
except Exception as e:
|
||||
logger.warning(f"Module [{name}] config validation error: {e}")
|
||||
return False, f"配置验证出错: {str(e)}"
|
||||
|
||||
# ========== 状态查询 ==========
|
||||
|
||||
def get_module_status(
|
||||
@@ -195,11 +223,28 @@ class ModuleRegistry:
|
||||
meta = module.metadata
|
||||
available = self.is_available(name)
|
||||
|
||||
# 获取配置验证状态
|
||||
config_validated = False
|
||||
config_error: Optional[str] = None
|
||||
if available:
|
||||
config_validated, config_error = self.validate_config(name, db)
|
||||
if config_validated:
|
||||
config_error = None # 验证通过时清空错误信息
|
||||
|
||||
# 获取启用状态
|
||||
enabled = self.is_enabled(name, db) if available else False
|
||||
|
||||
# 注意:配置验证失败时不自动禁用模块
|
||||
# 自动禁用会在查询方法中产生写操作副作用,违反幂等性原则
|
||||
# 配置验证状态通过 config_validated/config_error 字段返回,由调用方决定如何处理
|
||||
|
||||
return ModuleStatus(
|
||||
name=name,
|
||||
available=available,
|
||||
enabled=self.is_enabled(name, db) if available else False,
|
||||
enabled=enabled,
|
||||
active=self.is_active(name, db) if available else False,
|
||||
config_validated=config_validated,
|
||||
config_error=config_error,
|
||||
display_name=meta.display_name,
|
||||
description=meta.description,
|
||||
category=meta.category,
|
||||
|
||||
Reference in New Issue
Block a user