# 登录模块 ## 1. 模块概述 ### 1.1 设计原则 | 原则 | 说明 | | -------- | ----------------------------- | | **安全优先** | 传输全程加密,防暴力破解。 | | **角色分流** | 通过“内部员工登录”开关明确区分认证路由,杜绝权限越界。 | | **存量兼容** | 无缝兼容 SRM 存量供应商账号,降低用户迁移成本。 | | **体验极简** | 支持账号/手机双因子登录,并提供“记住我”与智能异常提示。 | ### 1.2 角色与认证路由映射 | 用户类型 | 开关状态 | 认证目标 | 说明 | | ---------- | --------- | -------------------- | ------------------------------------------------- | | **集团内部员工** | 开启(员工模式) | IAM(集团统一身份认证) | 跳转至 IAM 登录页或调用 OAuth2/OIDC 接口,不校验平台本地密码。 | | **外部供应商** | 关闭(供应商模式) | STP 本地用户表 / SRM 回退认证 | 优先校验 STP 本地账号;若不存在,自动路由至 SRM 验证(满足 SRM 存量用户无感登录)。 | ## 2. 页面布局与 UI 设计 ### 2.1 整体布局 ```svg 智慧招标平台 Smart Tendering Platform AI 原生 · 全流程线上闭环 · 主动式智能 覆盖公开招标 · 邀请招标 · 竞争性谈判 · 单一来源 欢迎登录 登录您的账户,开始智能招采之旅 👤 内部员工 🏢 外部账号 当前:内部员工模式(走 IAM 认证) 账号登录 手机验证码 账号 / 手机号 请输入您的账号 ! 密码 请输入您的密码 👁️ 记住我 忘记密码? 登 录 还没有账号? 立即注册 温馨提示 💡 原 SRM 注册用户,可直接使用 SRM 账号密码登录,无需重复注册。 © 2026 滨化集团 | 智慧招标平台 V1.0 ``` ### 2.2 账号登录页面 关键元素: * 账号输入框 * 密码输入框 * `记住我`选择框。 * `忘记密码`链接 * `登录`按钮 * `内部员工登录`选择框,选择后将走集团 IAM 路由进行身份认证,否则走平台账号路由进行身认证。 * `立即注册`链接 * 登录说明:原 SRM 注册用户,可直接使用 SRM账号密码登录,无需重复注册。 ### 2.3 手机验证码登录页面 关键元素: * 手机号输出框 * 验证码输出框 * 发送验证码按钮 * 登录按钮 ### 2.4 页面状态与元素交互说明 | UI 元素 | 交互行为 | 状态变化 | | ------------------- | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------ | | **内部员工 / 供应商 切换滑块** | 点击滑块或文字,滑块滑动至对应位置,下方提示文字切换,表单保持不变,但认证逻辑改变。 | 员工模式:下方显示`当前:内部员工模式(IAM 认证)`,且“忘记密码”链接跳转至 IAM 密码找回页;“立即注册”置灰或隐藏(员工由 HR 系统同步)。供应商模式:恢复常规提示。 | | **账号登录 / 手机登录 Tab** | 点击切换 Tab,下方表单内容切换。 | 账号登录:显示账号+密码框。手机登录:显示手机号+验证码框+发送验证码按钮。 | | **记住我** | 勾选后,登录成功时将 `refresh_token` 存入浏览器本地(Secure Storage),有效期为 7 天。 | 复选框状态持久化(基于本地 Cookie 记忆偏好)。 | | **忘记密码** | 供应商模式:跳转至“重置密码”页(需短信/邮箱验证)。员工模式:跳转至 IAM 统一认证的密码重置页面。 | 页面跳转。 | | **立即注册** | 供应商模式:跳转至供应商注册页(含 SRM 存量账号绑定引导)。员工模式:不可用(灰色)。 | 页面跳转 / 按钮置灰。 | ## 3.详细交互流程 ### 3.1 登录主流程 ```mermaid graph TD A[供应商访问STP门户] --> B{检测登录态?} B -->|有有效Token| C[无感跳转至工作台] B -->|无Token| D[展示登录页面] D --> E[输入账号/密码] E --> F{账号来源检测} F -->|STP本地账号| G[STP身份认证] F -->|SRM存量账号| H[调用Vendor SSO鉴权] G --> I{认证成功?} H --> I I -->|失败| J[显示错误信息
记录失败日志] J --> K{失败次数≥5?} K -->|是| L[锁定账号30分钟
触发安全告警] K -->|否| E I -->|成功| M{是否MFA启用?} M -->|是| N[发送短信验证码] N --> O[验证码校验] O -->|失败| N O -->|成功| P[生成JWT令牌] M -->|否| P P --> Q[更新最后登录信息] Q --> R[记录审计日志] R --> S[跳转至供应商工作台] ``` ### 3.2 时序图:多认证源详细交互 ```mermaid sequenceDiagram participant U as 用户/浏览器 participant FE as STP 前端 participant GW as API 网关 participant Auth as 认证服务 participant IAM as 集团 IAM participant LocalDB as STP 用户库 participant SRM as SRM 系统 U->>FE: 输入账号/密码,点击登录 FE->>FE: 前端基础校验(非空/格式) FE->>GW: POST /api/v1/auth/login { loginType, account, password, mode } alt 员工模式 (mode=employee) GW->>Auth: 转发至 IAM 认证处理器 Auth->>IAM: OAuth2/OIDC 密码模式 / LDAP 验证 IAM-->>Auth: 返回用户信息 (employeeId, dept, roles) Auth-->>Auth: 若成功,生成 STP 内部 Session Auth-->>FE: 200 OK { token, redirectUrl } else 供应商模式 (mode=vendor) GW->>Auth: 转发至本地认证处理器 Auth->>LocalDB: 查询 account alt 本地用户存在 LocalDB-->>Auth: 返回用户实体(含 salt, hash) Auth->>Auth: 校验密码(BCrypt/Argon2) else 本地用户不存在 Auth->>SRM: 调用 /api/v1/auth/login/for-stp { username, password } SRM-->>Auth: 200 { srmId, name, taxId, ... } Auth->>LocalDB: 创建影子用户(绑定 srmId) LocalDB-->>Auth: 返回新用户实体 end Auth-->>FE: 200 OK { token, vendorId, srmId, redirectUrl } end FE->>FE: 存储 Token 至 LocalStorage/Session FE-->>U: 302 重定向至工作台 ``` ### 3.3 手机验证码登录详细流程 ```mermaid sequenceDiagram participant U as 用户 participant FE as 前端 participant Auth as 认证服务 participant SMS as 短信网关 participant Cache as Redis 缓存 U->>FE: 输入手机号,点击“发送验证码” FE->>FE: 校验手机号格式(11位/国际格式) FE->>Auth: POST /api/v1/auth/sms/send { phone, captchaToken } Auth->>Auth: 校验图形验证码(防机器人) Auth->>Cache: 查询该手机号发送频率(60s内是否已发) alt 频率过高 Cache-->>Auth: 已发送,拒绝 Auth-->>FE: 429 Too Many Requests { remainSeconds: 45 } else 频率正常 Auth->>Auth: 生成6位随机验证码(如 882345) Auth->>Cache: 存储验证码至 Redis(Key: sms:login:{phone}, TTL: 5min) Auth->>SMS: 调用短信发送接口 SMS-->>Auth: 发送成功 Auth-->>FE: 200 OK { expireSeconds: 300 } FE-->>U: 开始倒计时(60s) end U->>FE: 输入验证码,点击“登录” FE->>Auth: POST /api/v1/auth/login/mobile { phone, code } Auth->>Cache: 读取验证码并比对 alt 验证码匹配 Cache-->>Auth: 匹配成功 Auth->>Auth: 查询或创建用户(若不存在则自动注册/绑定SRM) Auth-->>FE: 200 { token, isNewUser } else 验证码错误或过期 Auth-->>FE: 401 { code: "ERR_SMS_001", message: "验证码错误或已过期" } end ``` ## 4. 接口详细定义 ### 4.1 账号密码登录接口 |项目|内容| |---|---| |**路径**|`/api/v1/auth/login`| |**方法**|`POST`| |**是否认证**|否(公开接口)| **请求体** ```json { "account": "zhangli@binhai.com", // 账号/邮箱/手机号 "password": "abcsdfg", "mode": "vendor", // "employee" 或 "vendor" "back_url":"/index" //返回的链接,可省略 "rememberMe": true // 是否记住我 } ``` **成功响应(200)** ```json { "code": "0", "data": { "accessToken": "eyJhbGciOiJSUzI1NiIs...", "refreshToken": "dGhpcyBpcyBhIHJlZnJlc2ggdG9rZW4...", "expiresIn": 1800, "userInfo": { "userId": "U_20240001", "userType": "VENDOR", // EMPLOYEE / VENDOR "name": "张立", "srmId": "SRM_12345", // 若存在关联 "roles": ["SUPPLIER"], "redirectUrl": "/dashboard/vendor" } } } ``` **失败响应(401)** ```json { "code": "ERR_AUTH_001", "message": "账号或密码错误", "remainingAttempts": 4 } ``` ### 4.2 手机验证码发送接口 |项目|内容| |---|---| |**路径**|`/api/v1/auth/sms/send`| |**方法**|`POST`| **请求体** ```json { "phone": "13800138000", "captchaToken": "a1b2c3d4" // 图形验证码 token "mode": "vendor", // "employee" 或 "vendor" "back_url":"/index" //返回的链接,可省略 "rememberMe": true // 是否记住我 } ``` **成功响应** ```json { "code": "0", "data": { "expireSeconds": 300, "resendAfterSeconds": 60 } } ``` ## 5. 安全设计细项 | 维度 | 具体策略 | | -------------- | ----------------------------------------------------------------------------------------------------- | | **传输加密** | 强制 HTTPS/TLS 1.3,禁用弱加密套件。 | | **密码存储** | 使用 **Argon2id** 或 **BCrypt(cost≥10)** 加盐哈希存储。 | | **防暴力破解** | 单账号 5 次失败后锁定 30 分钟(IP 维度 20 次失败后全局验证码强制)。 | | **JWT 安全** | 算法使用 RS256(私钥签名,公钥验签);Access Token 有效期 30 分钟;Refresh Token 有效期 7 天,存储于 HTTPOnly Secure Cookie(防 XSS)。 | | **验证码安全** | 手机验证码 6 位数字,有效期 5 分钟;发送间隔限制 60 秒;单日单号码上限 10 条。 | | **登录审计** | 记录:用户 ID、登录时间、IP、User-Agent、设备指纹(Canvas Fingerprint)、认证源(IAM/Local/SRM)。审计日志写入哈希链(见《需求说明书》4.8.1)。 | | **多因素认证(MFA)** | 预留扩展接口。敏感操作(修改密码、更换手机)强制二次验证。 | | **会话并发** | 默认允许同一账号多设备登录,==但可在管理后台启用“单点登录互踢”策略(保留配置项)==。 | ## 6. 异常场景与错误码矩阵 | 异常场景 | 错误码 | HTTP 状态码 | 用户提示 | 后端处理 | | --------------- | --------------- | -------- | ----------------- | ---------- | | 账号为空 | `ERR_PARAM_001` | 400 | 请输入账号 | 无 | | 密码为空 | `ERR_PARAM_002` | 400 | 请输入密码 | 无 | | 账号/密码不匹配(本地) | `ERR_AUTH_001` | 401 | 账号或密码错误 | 失败计数 + 1 | | 账号不存在且 SRM 验证失败 | `ERR_AUTH_002` | 401 | 账号不存在,请检查或注册 | 记录未注册尝试 | | 账号已锁定 | `ERR_AUTH_003` | 403 | 账号已被锁定,请 30 分钟后重试 | 告警(若为频繁攻击) | | 手机号格式错误 | `ERR_PARAM_003` | 400 | 请输入正确的手机号 | 无 | | 验证码发送频率过高 | `ERR_SMS_001` | 429 | 发送过于频繁,请 60 秒后重试 | 返回剩余秒数 | | 验证码错误/过期 | `ERR_SMS_002` | 401 | 验证码错误或已过期 | 清除已用验证码 | | IAM 认证超时 | `ERR_IAM_001` | 504 | 集团认证服务繁忙,请稍后重试 | 熔断降级,记录日志 | ## 7. 登录成功后的路由与权限门控 登录成功后,前端根据 `userType` 和 `roles` 决定跳转目标,同时后端在后续请求中通过 **JWT** 持续校验权限。 | 用户类型 | 默认跳转页面 | 可访问范围 | | ------------------ | --------------------- | ------------------------------------- | | **供应商(VENDOR)** | `/portal/dashboard` | 招标公告列表、报名管理、我的投标、中标通知、保证金管理。 | | **评审专家(EXPERT)** | `/expert/dashboard` | 评标任务列表、回避申报、承诺书签署、历史评审记录。 | | **内部员工(EMPLOYEE)** | `/employee/dashboard` | 根据子角色(需求人员/招标专员/审批人/管理员)展示对应工作台。 | | **系统管理员(ADMIN)** | `/admin/console` | 用户管理、流程配置、审计日志、系统监控。
(管理员不在普通页面登录) | ```mermaid graph LR A[登录成功] --> B{UserType} B -->|VENDOR| C[供应商工作台] B -->|EXPERT| D[专家工作台] B -->|EMPLOYEE| E{子角色} E -->|需求人员| F[需求工作台] E -->|招标专员| G[招标管理工作台] E -->|审批人| H[审批待办中心] E -->|管理员| I[系统管理后台] style A fill:#e8f5e9,stroke:#388e3c style C fill:#e3f2fd,stroke:#1565c0 style D fill:#fff3e0,stroke:#e65100 style I fill:#fce4ec,stroke:#c2185b ``` ## 8. 与 SRM 无感登录的集成衔接 登录页下方的 **“原 SRM 注册用户,可直接使用 SRM账号密码登录”** 提示对应后端自动回退逻辑(详见 3.2 时序图)。此外,登录成功后,前端页面内嵌的指向 SRM 的所有链接,将自动携带 **跳转票据(Ticket)** 实现无感跳转(技术方案详见《SRM 与 STP 数据交换接口方案说明书》3.4.2 节)。