checkpoint: 架构治理四件套——统一 async / 测试真 PG / Redis 降级可选 / DPB 扶正
- A1 业务层统一 async:gencode 表内省改 run_sync 异步(不再阻塞事件循环)、 check_db 改 async_engine、dict_util 启动预热异步载入;psycopg 降为 APScheduler SQLAlchemyJobStore 专用同步孤岛(注释标注) - A2 测试真 PG 化:conftest 弃 SQLite + mock Redis,改连真实 PG16(dpb_test)+ Redis(number_gen advisory lock 路径真被测);新增 docker/test-compose.yaml 测试依赖栈(postgres:16:5433 + redis:7:6380);run_ci 前置探测 + 容器兜底, pytest -m pg 10 套正式 tc 全过(真实 PG16 + Redis) - B1 Redis 启动不强依赖:redis_connect 失败降级启动,缓存类回源 DB、存储类 (会话/AI 配置/调度)经 require_redis 守卫返回 503;真机 3 阶段降级测试 PASS=11 FAIL=0(独立 Redis 6390 + 后端 8091,不动共享 dev 服务) - C 扶正 DPB:后端横幅/日志(dpb.log)/README/pyproject/ai_factory agent 名、 前端 package.json/署名注释/链接文案/deploy.sh/docker 注释全部去 fastapiadmin; grep backend/app + frontend/web/src 零残留 - 验证:全量回归 pass=72 fail=0
This commit is contained in:
@@ -14,7 +14,7 @@ from app.api.v1.module_system.log.model import LoginLogModel
|
||||
from app.api.v1.module_system.log.schema import LoginLogCreateSchema
|
||||
from app.api.v1.module_system.user.crud import UserCRUD
|
||||
from app.api.v1.module_system.user.model import UserModel
|
||||
from app.common.enums import RedisInitKeyConfig
|
||||
from app.common.enums import RET, RedisInitKeyConfig
|
||||
from app.config.setting import settings
|
||||
from app.core.base_schema import AuthSchema, JWTOutSchema, JWTPayloadSchema
|
||||
from app.core.database import async_db_session
|
||||
@@ -165,6 +165,13 @@ class LoginService:
|
||||
"""用户认证"""
|
||||
ua_result = ua_parser.parse(request.headers.get("user-agent") or "")
|
||||
request_ip = get_client_ip(request)
|
||||
if redis is None:
|
||||
# 会话存储不可用:登录即使成功也无法建立可用会话,明确 503
|
||||
raise CustomException(
|
||||
msg="Redis 服务不可用,无法建立登录会话",
|
||||
code=RET.SERVICE_UNAVAILABLE.code,
|
||||
status_code=503,
|
||||
)
|
||||
login_location = await IpLocalUtil.resolve_location_for_log(redis, request_ip)
|
||||
|
||||
# 暴力破解防护:先检查该用户名+IP 是否已被锁定(Redis 故障时跳过,避免锁死系统)
|
||||
@@ -329,6 +336,13 @@ class LoginService:
|
||||
@classmethod
|
||||
async def create_token(cls, request: Request, redis: Redis, user: UserModel, login_type: str) -> JWTOutSchema:
|
||||
"""创建访问令牌和刷新令牌"""
|
||||
if redis is None:
|
||||
# 会话信息仅存 Redis;降级模式下建出的 token 无法通过后续会话校验,直接 503
|
||||
raise CustomException(
|
||||
msg="Redis 服务不可用,无法建立登录会话",
|
||||
code=RET.SERVICE_UNAVAILABLE.code,
|
||||
status_code=503,
|
||||
)
|
||||
session_id = str(uuid.uuid4())
|
||||
ua_result = ua_parser.parse(request.headers.get("user-agent") or "")
|
||||
request_ip = get_client_ip(request)
|
||||
@@ -406,6 +420,12 @@ class LoginService:
|
||||
token_payload: JWTPayloadSchema = decode_access_token(token=refresh_token)
|
||||
if not token_payload.is_refresh:
|
||||
raise CustomException(msg="非法凭证,请传入刷新令牌")
|
||||
if redis is None:
|
||||
raise CustomException(
|
||||
msg="Redis 服务不可用,无法刷新会话",
|
||||
code=RET.SERVICE_UNAVAILABLE.code,
|
||||
status_code=503,
|
||||
)
|
||||
|
||||
session_id = token_payload.sub
|
||||
session_info = await RedisCURD(redis).get(f"{RedisInitKeyConfig.USER_SESSION.key}:{session_id}")
|
||||
|
||||
Reference in New Issue
Block a user