feat(merge): 4 个 worktree 合入 main(扫码+MFA+高危+P0)
合入内容: - worktree-A (auth_qrcode): 13 测试 ✅ — Phase 1.1 后端扫码登录 - worktree-B (mfa): 21 测试 ✅ — Phase 2.1 MFA TOTP + User 字段 - worktree-C (high_risk_guard): 28 测试 ✅ — Phase 1.3 高危守卫 - worktree-D (p0-fixes): 16 测试 ✅ — P0/P1 合规(WS 签名+UUID+access_log) 合并方式: 各 worktree 提取 format-patch → 只 apply 新增文件 → 手动合并 router.py/dependencies.py 冲突 新文件 (16): backend/alembic/versions/022_qrcode_login.py backend/alembic/versions/023_mfa_fields.py backend/alembic/versions/025_messages_id_uuid.py backend/app/api/auth_qrcode.py backend/app/api/high_risk_routes.py backend/app/api/mfa.py backend/app/schemas/mfa.py backend/app/schemas/qrcode.py backend/app/services/high_risk_guard.py backend/app/services/mfa_service.py backend/app/services/qrcode_service.py backend/scripts/nginx-access-log-sanitize.sh backend/tests/test_auth_qrcode.py (13) backend/tests/test_high_risk_guard.py (28) backend/tests/test_mfa.py (21) backend/tests/test_messages_uuid.py backend/tests/test_ws_endpoints.py backend/tests/test_ws_push_to_employee.py (xfail 4) 修改 (4): backend/app/api/router.py — 注册 auth_qrcode/high_risk_routes/mfa 3 个 router backend/app/dependencies.py — 加 HIGH_RISK_OPERATIONS + require_high_risk_otp backend/app/models/agent.py — mfa_secret/mfa_enabled/mfa_bound_at/mfa_last_verified_at backend/tests/conftest.py — create_test_conversation 接 db_session 测试结果(新增 78 + xfail 4): tests/test_auth_qrcode.py 13 passed tests/test_high_risk_guard.py 28 passed tests/test_mfa.py 21 passed tests/test_messages_uuid.py 8 passed tests/test_ws_endpoints.py 8 passed tests/test_ws_push_to_employee.py 4 xfailed (端点路径不一致,pre-existing) 4 端 frontend build 全部通过(agent/portal/admin/h5) 后续 TODO (用户操作): 1. 撤销 Gitea token 5ad83d... via Web UI 2. 跑 alembic upgrade head(生产 PG,025 messages UUID) 3. 应用 nginx access_log 脱敏(进容器改 conf) 4. 部署 backend + 4 端 dist + nginx reload Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -9,7 +9,7 @@ import uuid
|
||||
from datetime import datetime
|
||||
from typing import Optional
|
||||
|
||||
from sqlalchemy import DateTime, Integer, JSON, String
|
||||
from sqlalchemy import Boolean, DateTime, Integer, JSON, String, text
|
||||
from sqlalchemy.orm import Mapped, mapped_column
|
||||
|
||||
from app.database import Base
|
||||
@@ -150,6 +150,44 @@ class Agent(Base):
|
||||
comment="本地密码哈希(bcrypt)",
|
||||
)
|
||||
|
||||
# --------------------------------------------------------------------------
|
||||
# MFA 二次认证字段(Phase 2.1 task #17)
|
||||
# --------------------------------------------------------------------------
|
||||
# 说明:MFA TOTP 独立于早期 OTP 字段,采用全新字段名以便区分演进阶段。
|
||||
# - mfa_secret: TOTP 共享密钥(base32),绑定时生成,首次验证前不算启用
|
||||
# - mfa_enabled: 是否启用(仅当 bind/confirm 验证成功后置 true)
|
||||
# - mfa_bound_at: 首次绑定完成时间(用于审计 + 回收策略)
|
||||
# - mfa_last_verified_at: 最近一次 verify 成功时间(用于安全审计)
|
||||
# --------------------------------------------------------------------------
|
||||
mfa_secret: Mapped[Optional[str]] = mapped_column(
|
||||
String(32),
|
||||
nullable=True,
|
||||
default=None,
|
||||
comment="MFA TOTP 共享密钥(base32,绑定时生成)",
|
||||
)
|
||||
|
||||
mfa_enabled: Mapped[bool] = mapped_column(
|
||||
Boolean,
|
||||
nullable=False,
|
||||
default=False,
|
||||
server_default=text("false"),
|
||||
comment="MFA 是否启用(False/True)",
|
||||
)
|
||||
|
||||
mfa_bound_at: Mapped[Optional[datetime]] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
nullable=True,
|
||||
default=None,
|
||||
comment="MFA 首次绑定完成时间",
|
||||
)
|
||||
|
||||
mfa_last_verified_at: Mapped[Optional[datetime]] = mapped_column(
|
||||
DateTime(timezone=True),
|
||||
nullable=True,
|
||||
default=None,
|
||||
comment="MFA 最近一次验证成功时间",
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
"""坐席对象的字符串表示,方便调试。"""
|
||||
return (
|
||||
|
||||
Reference in New Issue
Block a user