refactor: inject token runtime configuration

This commit is contained in:
jxxghp
2026-08-23 01:14:12 +08:00
parent 5395bbff54
commit 690ebe0c02
8 changed files with 75 additions and 12 deletions
+26
View File
@@ -72,6 +72,16 @@ class TransferRetryConfig:
max_failed_retries: Any
@dataclass(frozen=True, slots=True)
class TokenRuntimeConfig:
"""令牌编解码在一次宿主生命周期内使用的安全配置快照。"""
secret_key: str
resource_secret_key: str
access_token_expire_minutes: int
resource_access_token_expire_seconds: int
@dataclass(frozen=True, slots=True)
class ApiRuntimeConfig:
"""单次 API 请求使用的宿主配置快照。"""
@@ -318,6 +328,7 @@ class SystemConfigService:
_configured_system_config: SystemConfigService | None = None
_transfer_retry_config_provider: Callable[[], TransferRetryConfig] | None = None
_token_runtime_config_provider: Callable[[], TokenRuntimeConfig] | None = None
_runtime_configuration: RuntimeConfiguration | None = None
_runtime_settings_service: RuntimeSettingsService | None = None
@@ -350,6 +361,21 @@ def get_transfer_retry_config() -> TransferRetryConfig:
return _transfer_retry_config_provider()
def configure_token_runtime_config(
provider: Callable[[], TokenRuntimeConfig],
) -> None:
"""由启动组合根登记令牌安全配置快照工厂。"""
global _token_runtime_config_provider
_token_runtime_config_provider = provider
def get_token_runtime_config() -> TokenRuntimeConfig:
"""返回当前令牌编解码使用的不可变配置快照。"""
if _token_runtime_config_provider is None:
raise RuntimeError("令牌运行时配置尚未装配")
return _token_runtime_config_provider()
def configure_runtime_configuration(configuration: RuntimeConfiguration) -> None:
"""由启动组合根登记各运行面使用的类型化配置快照工厂。"""
global _runtime_configuration
+26 -7
View File
@@ -4,6 +4,7 @@ import base64
import datetime
import hashlib
import hmac
import importlib
import json
import os
import traceback
@@ -16,7 +17,7 @@ from Crypto.Cipher import AES
from Crypto.Util.Padding import pad
from cryptography.fernet import Fernet
from app.runtime.config import settings
from app.application.configuration import TokenRuntimeConfig, get_token_runtime_config
from app.runtime.log import logger
from app.schemas.token import TokenPayload
@@ -25,6 +26,22 @@ BCRYPT_ROUNDS = 12
ALGORITHM = "HS256"
def _token_config() -> TokenRuntimeConfig:
"""读取启动快照;未装配时保留旧插件的独立调用兼容。"""
try:
return get_token_runtime_config()
except RuntimeError:
legacy_settings = importlib.import_module("app.runtime.config").settings
return TokenRuntimeConfig(
secret_key=legacy_settings.SECRET_KEY,
resource_secret_key=legacy_settings.RESOURCE_SECRET_KEY,
access_token_expire_minutes=legacy_settings.ACCESS_TOKEN_EXPIRE_MINUTES,
resource_access_token_expire_seconds=(
legacy_settings.RESOURCE_ACCESS_TOKEN_EXPIRE_SECONDS
),
)
class PasswordTooLongError(ValueError):
"""密码的 UTF-8 字节长度超过 bcrypt 可安全处理的上限。"""
@@ -58,14 +75,15 @@ def create_access_token(
purpose: Optional[str] = "authentication",
) -> str:
"""创建带身份、权限等级和用途声明的 JWT 访问令牌。"""
config = _token_config()
if purpose == "resource":
default_expire = timedelta(
seconds=settings.RESOURCE_ACCESS_TOKEN_EXPIRE_SECONDS
seconds=config.resource_access_token_expire_seconds
)
secret_key = settings.RESOURCE_SECRET_KEY
secret_key = config.resource_secret_key
else:
default_expire = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
secret_key = settings.SECRET_KEY
default_expire = timedelta(minutes=config.access_token_expire_minutes)
secret_key = config.secret_key
if expires_delta is not None:
if expires_delta.total_seconds() <= 0:
@@ -92,12 +110,13 @@ def decode_access_token(
purpose: str = "authentication",
) -> TokenPayload:
"""校验 JWT 签名和用途并返回框架无关的令牌载荷。"""
config = _token_config()
if not token:
raise TokenValidationError(f"{purpose} token not found")
secret_key = (
settings.RESOURCE_SECRET_KEY
config.resource_secret_key
if purpose == "resource"
else settings.SECRET_KEY
else config.secret_key
)
try:
payload = jwt.decode(token, secret_key, algorithms=[ALGORITHM])
+11
View File
@@ -6,6 +6,7 @@ from app.application.configuration import (
ApiRuntimeConfig,
ChainRuntimeConfig,
SchedulerRuntimeConfig,
TokenRuntimeConfig,
)
from app.runtime.config import Settings
from app.schemas.types import MediaType
@@ -52,6 +53,16 @@ def build_api_runtime_config(settings: Settings) -> ApiRuntimeConfig:
)
def build_token_runtime_config(settings: Settings) -> TokenRuntimeConfig:
"""从部署设置构建令牌编解码使用的安全配置快照。"""
return TokenRuntimeConfig(
secret_key=settings.SECRET_KEY,
resource_secret_key=settings.RESOURCE_SECRET_KEY,
access_token_expire_minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES,
resource_access_token_expire_seconds=settings.RESOURCE_ACCESS_TOKEN_EXPIRE_SECONDS,
)
def build_scheduler_runtime_config(settings: Settings) -> SchedulerRuntimeConfig:
"""从可热更新的部署设置构建一次 Scheduler 配置快照。"""
return SchedulerRuntimeConfig(
+3
View File
@@ -42,6 +42,7 @@ from app.application.configuration import (
SystemConfigService,
get_configured_system_config,
TransferRetryConfig,
configure_token_runtime_config,
configure_runtime_configuration,
configure_runtime_settings,
configure_system_config,
@@ -51,6 +52,7 @@ from app.startup.configuration import (
build_api_runtime_config,
build_chain_runtime_config,
build_scheduler_runtime_config,
build_token_runtime_config,
)
from app.application.database import configure_database_governance
from app.application.service import configure_service_directory
@@ -594,6 +596,7 @@ async def init_modules() -> HostRuntime:
)
configure_runtime_configuration(host_runtime.configuration)
configure_runtime_settings(host_runtime.settings)
configure_token_runtime_config(lambda: build_token_runtime_config(settings))
# 先发布系统配置服务,后续启动组合步骤统一复用同一配置端口。
configure_system_config(SystemConfigService(repository=SystemConfigOper()))
# 旧 app.api.data 导入只保留 ABI 转发,正式 API 依赖全部读取 HostRuntime。