2026-07-07 21:52:11 +08:00
|
|
|
|
sequenceDiagram
|
2026-07-09 11:50:19 +08:00
|
|
|
|
participant User as 坐席
|
|
|
|
|
|
participant LoginVue as Login.vue
|
|
|
|
|
|
participant AgentStore as agentStore
|
|
|
|
|
|
participant OtpBind as OtpBindPanel.vue
|
|
|
|
|
|
participant API as apiClient
|
|
|
|
|
|
participant Backend as FastAPI Backend
|
|
|
|
|
|
participant Redis as Redis
|
2026-07-07 21:52:11 +08:00
|
|
|
|
|
2026-07-09 11:50:19 +08:00
|
|
|
|
User->>LoginVue: 输入账号密码 → 点击登录
|
|
|
|
|
|
LoginVue->>AgentStore: login(userId, password, undefined)
|
|
|
|
|
|
AgentStore->>API: POST /api/agents/login {user_id, password}
|
|
|
|
|
|
API->>Backend: agent_login()
|
|
|
|
|
|
|
|
|
|
|
|
Note over Backend: agent.mfa_enabled == False
|
|
|
|
|
|
Backend-->>API: { require_otp_bind: true, user_id, name, role }
|
|
|
|
|
|
API-->>AgentStore: { require_otp_bind: true, ... }
|
|
|
|
|
|
AgentStore-->>LoginVue: return { require_otp_bind: true }
|
2026-07-07 21:52:11 +08:00
|
|
|
|
|
2026-07-09 11:50:19 +08:00
|
|
|
|
Note over LoginVue: 隐藏账密表单<br/>显示 OtpBindPanel
|
|
|
|
|
|
LoginVue->>OtpBind: requireOtpBind = true
|
2026-07-07 21:52:11 +08:00
|
|
|
|
|
2026-07-09 11:50:19 +08:00
|
|
|
|
OtpBind->>API: POST /api/auth/otp-bind
|
|
|
|
|
|
API->>Backend: bind_otp()
|
|
|
|
|
|
Note over Backend: 生成 secret + QR
|
|
|
|
|
|
Backend-->>API: { secret, otpauth_url, qr_code_base64 }
|
|
|
|
|
|
API-->>OtpBind: { secret, otpauth_url, qr_code_base64 }
|
|
|
|
|
|
|
|
|
|
|
|
Note over OtpBind: 渲染二维码 + secret 明文
|
|
|
|
|
|
User->>User: 用 Authenticator 扫码(或手动输入 secret)
|
|
|
|
|
|
User->>OtpBind: 输入 6 位验证码 → 点击"验证并完成绑定"
|
|
|
|
|
|
|
|
|
|
|
|
OtpBind->>API: POST /api/auth/otp-verify { otp_code }
|
|
|
|
|
|
API->>Backend: verify_otp()
|
|
|
|
|
|
|
|
|
|
|
|
Note over Backend: mfa_enabled=False (绑定场景)<br/>校验 TOTP → 通过<br/>设置 mfa_enabled=True<br/>设置 mfa_bound_at=now
|
|
|
|
|
|
|
|
|
|
|
|
Backend->>Redis: mark_verified(employee_id, TTL=1800)
|
|
|
|
|
|
Backend->>Backend: 签发 JWT token
|
|
|
|
|
|
Backend-->>API: { verified: true, token, user_id, name, role }
|
|
|
|
|
|
API-->>OtpBind: { verified: true, token, ... }
|
|
|
|
|
|
|
|
|
|
|
|
OtpBind-->>LoginVue: emit('bind-success', { token, user_id, name })
|
|
|
|
|
|
LoginVue->>AgentStore: 保存 token → 设置 agentInfo
|
|
|
|
|
|
LoginVue->>LoginVue: router.push('/workspace')
|