42 lines
2.2 KiB
Markdown
42 lines
2.2 KiB
Markdown
# 2026-05-25 — 服务器表单 UX 重构:预设下拉菜单 + SSH 密钥输入
|
||
|
||
## 变更摘要
|
||
|
||
重构服务器添加/编辑 Modal 的认证区域:
|
||
1. 密码预设从🔑弹窗 + prompt()二次验证 → `<select>` 下拉菜单,选预设后密码框自动隐藏,后端自动解析
|
||
2. SSH 密钥模式新增「私钥内容」textarea,支持直接粘贴 PEM 格式私钥
|
||
3. Server 模型新增 `preset_id` 字段,关联密码预设
|
||
|
||
## 动机
|
||
|
||
- 旧方案:点击🔑按钮 → 浮层弹窗 → prompt() 输入登录密码 → 解密预设 → 填入密码框。流程冗长,且 prompt() 不安全(明文密码出现在 JS 变量中)
|
||
- 新方案:直接选预设下拉 → 密码框自动隐藏 → 保存时后端自动解密预设密码并加密存储。零前端密码暴露
|
||
- 密钥模式之前只有「密钥路径」,无法粘贴私钥内容,功能缺失
|
||
|
||
## 涉及文件
|
||
|
||
| 文件 | 改动 |
|
||
|------|------|
|
||
| `server/domain/models/__init__.py` | Server 新增 `preset_id` 列 |
|
||
| `server/api/schemas.py` | ServerCreate/ServerUpdate 新增 `preset_id` 字段 |
|
||
| `server/api/servers.py` | create_server/update_server 自动解析预设密码;`ssh_key_private` 时自动设 `ssh_key_configured=True`;`_server_to_dict` 输出 `preset_id` |
|
||
| `web/app/servers.html` | Modal 重构:密码区=预设下拉+密码输入框(联动);密钥区=路径+私钥textarea;删除旧 preset 弹窗代码 |
|
||
|
||
## 是否需迁移/重启
|
||
|
||
- **DB 迁移**: `ALTER TABLE servers ADD COLUMN preset_id INT NULL COMMENT '关联的密码预设ID(SSH认证)' AFTER agent_api_key;`
|
||
- **需重启**: 是(Python 后端模型+路由变更)
|
||
|
||
## 安全考量
|
||
|
||
- 前端不再接触预设密码明文 → 减少攻击面
|
||
- `preset_id` 仅在后端解析,前端只传 ID → 无 XSS 泄露风险
|
||
- 预设不存在时静默忽略,不报错(用户仍可手动输入密码)
|
||
|
||
## 验证方式
|
||
|
||
1. 打开添加服务器 → 密码模式:预设下拉可见,选预设后密码框隐藏
|
||
2. 切换到密钥模式:密钥路径+私钥内容 textarea 可见,密码区隐藏
|
||
3. API 测试 `POST /servers/` 传 `preset_id=2` → 返回 `password_set:true, preset_id:2`
|
||
4. API 测试 `POST /servers/` 传 `ssh_key_private` → 返回 `ssh_key_configured:true, ssh_key_private_set:true`
|