[SEN] 将全模式密码最短长度调整为6位 #41
@@ -9,8 +9,8 @@ import (
|
||||
)
|
||||
|
||||
func ValidatePassword(username, password string) error {
|
||||
if len([]rune(password)) < 12 {
|
||||
return fmt.Errorf("密码至少需要 12 个字符")
|
||||
if len([]rune(password)) < 6 {
|
||||
return fmt.Errorf("密码至少需要 6 个字符")
|
||||
}
|
||||
var upper, lower, digit bool
|
||||
for _, value := range password {
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package identity
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestValidatePasswordLengthAndComplexity(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
username string
|
||||
password string
|
||||
want string
|
||||
}{
|
||||
{name: "six characters", username: "operator", password: "Abc123"},
|
||||
{name: "five characters", username: "operator", password: "Ab123", want: "至少需要 6 个字符"},
|
||||
{name: "missing uppercase", username: "operator", password: "abc123", want: "大写字母、小写字母和数字"},
|
||||
{name: "missing lowercase", username: "operator", password: "ABC123", want: "大写字母、小写字母和数字"},
|
||||
{name: "missing digit", username: "operator", password: "Abcdef", want: "大写字母、小写字母和数字"},
|
||||
{name: "contains username", username: "admin", password: "MyAdmin1", want: "不能包含用户名"},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
err := ValidatePassword(test.username, test.password)
|
||||
if test.want == "" {
|
||||
if err != nil {
|
||||
t.Fatalf("ValidatePassword() error = %v", err)
|
||||
}
|
||||
return
|
||||
}
|
||||
if err == nil || !strings.Contains(err.Error(), test.want) {
|
||||
t.Fatalf("ValidatePassword() error = %v, want substring %q", err, test.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@
|
||||
<el-form-item label="用户名" prop="username"><el-input v-model="form.username" :disabled="Boolean(editingID)" /></el-form-item>
|
||||
<el-form-item label="姓名" prop="display_name"><el-input v-model="form.display_name" /></el-form-item>
|
||||
<el-form-item label="角色" prop="role"><el-select v-model="form.role" style="width: 100%"><el-option v-for="role in roles" :key="role.value" :label="role.label" :value="role.value" /></el-select></el-form-item>
|
||||
<el-form-item v-if="!editingID" label="初始密码" prop="password"><el-input v-model="form.password" type="password" show-password /><div class="field-hint">至少 12 位,包含大小写字母和数字,且不含用户名。</div></el-form-item>
|
||||
<el-form-item v-if="!editingID" label="初始密码" prop="password"><el-input v-model="form.password" type="password" show-password /><div class="field-hint">至少 6 位,包含大小写字母和数字,且不含用户名。</div></el-form-item>
|
||||
<el-form-item v-else label="状态"><el-switch v-model="form.enabled" active-text="启用" inactive-text="停用" /></el-form-item>
|
||||
</el-form>
|
||||
<template #footer><el-button @click="dialogVisible = false">取消</el-button><el-button type="primary" :loading="saving" @click="save">保存</el-button></template>
|
||||
@@ -64,7 +64,7 @@ const rules = {
|
||||
username: [{ required: true, message: '请输入用户名', trigger: 'blur' }],
|
||||
display_name: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
|
||||
role: [{ required: true, message: '请选择角色', trigger: 'change' }],
|
||||
password: [{ required: true, min: 12, message: '请输入至少 12 位初始密码', trigger: 'blur' }]
|
||||
password: [{ required: true, min: 6, message: '请输入至少 6 位初始密码', trigger: 'blur' }]
|
||||
}
|
||||
const canWrite = computed(() => store.getters['sense-identity/hasPermission']?.('identity.users.write'))
|
||||
const filteredUsers = computed(() => {
|
||||
@@ -99,4 +99,3 @@ onMounted(load)
|
||||
<style scoped>
|
||||
.field-hint { color: #86909c; font-size: 12px; line-height: 1.5; }
|
||||
</style>
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
generated: true (请先修改 Gitea Wiki,禁止直接编辑本文件)
|
||||
wiki_page: Business-Rules-and-Glossary
|
||||
wiki_url: https://git.ilapage.cn/ila/yovision/wiki/Business-Rules-and-Glossary.-
|
||||
wiki_revision: 2b222ffc8c2d943fa2a27d9e28ffaf4896143950
|
||||
synchronized_at: 2026-08-12T10:21:57Z
|
||||
wiki_revision: fbb85952429813bb3da7e3cd8526ec03bc0dac0d
|
||||
synchronized_at: 2026-08-13T00:52:39Z
|
||||
<!-- gitea-wiki-mirror:end -->
|
||||
|
||||
# 业务规则与术语
|
||||
@@ -71,7 +71,7 @@ synchronized_at: 2026-08-12T10:21:57Z
|
||||
## Sense MVP 业务与安全规则
|
||||
|
||||
- **Sense 账户**:只登录 Sense;不得接受 Bell JWT、Cookie 或用户数据。角色为系统管理员、实施/运维、站点管理员和只读用户,后端权限是最终边界。
|
||||
- **安全初始化**:系统不提供默认账户、默认密码或默认签名密钥;首次管理员由仓库外一次性令牌创建。
|
||||
- **安全初始化**:系统不提供默认账户、默认密码或默认签名密钥;首次管理员由仓库外一次性令牌创建。所有模式的密码至少 6 个字符,必须同时包含大写字母、小写字母和数字,且不得包含用户名。该最短长度由负责人在已知生产安全风险后明确确认。
|
||||
- **Device**:设备不可变逻辑 ID 是后续 Profile、媒体和区域的内部引用。非视频适配器未实现时必须显示 `adapter_not_ready`。
|
||||
- **摄像机凭据**:只写不读,使用仓库外 32 字节密钥加密;不得进入 URL、日志、审计、工单或响应。
|
||||
- **受控发现**:ONVIF Discovery 默认关闭,只有显式设置获准本机 IP 才能发送发现;不得扫描未授权网段。
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
generated: true (请先修改 Gitea Wiki,禁止直接编辑本文件)
|
||||
wiki_page: Delivery-Documentation-Guide
|
||||
wiki_url: https://git.ilapage.cn/ila/yovision/wiki/Delivery-Documentation-Guide.-
|
||||
wiki_revision: 8127e9a6e6a92ed192639232bdc8813f5a9dea51
|
||||
synchronized_at: 2026-08-12T10:25:18Z
|
||||
wiki_revision: 2cf0a0f2f261c002866c86c4e70b5f6ed89f9c1c
|
||||
synchronized_at: 2026-08-13T00:53:04Z
|
||||
<!-- gitea-wiki-mirror:end -->
|
||||
|
||||
# 交付文档指南
|
||||
@@ -84,7 +84,7 @@ synchronized_at: 2026-08-12T10:25:18Z
|
||||
|
||||
Sense 面向网管、实施人员和非技术现场人员,菜单按日常任务组织:工作台 → 设备管理 → 视频接入 → 视频服务 → 实时监看 → 区域与警戒线。普通操作优先展示中文状态与下一步,不要求用户理解 ONVIF、RTSP 或 MediaMTX 内部模型。
|
||||
|
||||
- 系统管理员:完成一次性安全初始化,维护 Sense 用户与角色,查看操作记录。
|
||||
- 系统管理员:完成一次性安全初始化,维护 Sense 用户与角色,查看操作记录。首次管理员和新用户密码至少 6 个字符,必须同时包含大写字母、小写字母和数字,且不得包含用户名。
|
||||
- 实施/运维:添加设备、只写更新凭据、在获准网卡发现或手工接入、检查主辅码流、处理媒体进程与对账。
|
||||
- 站点管理员:查看/维护站点设备,实时监看,绘制和发布区域版本;无权创建系统管理员。
|
||||
- 只读用户:查看设备、媒体状态、实时画面和区域,不能修改。
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
<!-- gitea-wiki-mirror:start -->
|
||||
generated: true (请先修改 Gitea Wiki,禁止直接编辑本文件)
|
||||
wiki_page: Task-40-Sense全模式密码最短6位
|
||||
wiki_url: https://git.ilapage.cn/ila/yovision/wiki/Task-40-Sense%E5%85%A8%E6%A8%A1%E5%BC%8F%E5%AF%86%E7%A0%81%E6%9C%80%E7%9F%AD6%E4%BD%8D.-
|
||||
wiki_revision: 89cf46b02ed85e26165cd835ccebb78a6621aa8b
|
||||
synchronized_at: 2026-08-13T01:00:27Z
|
||||
<!-- gitea-wiki-mirror:end -->
|
||||
|
||||
# 40 Sense全模式密码最短6位
|
||||
|
||||
- 类型:需求变更
|
||||
- 所属 Epic:#7
|
||||
- 所属 MVP / 版本:#8
|
||||
- 状态:待验收
|
||||
- 日期:2026-08-13
|
||||
- Gitea 工单:https://git.ilapage.cn/ila/yovision/issues/40
|
||||
- Wiki 页面:Task-40-Sense全模式密码最短6位
|
||||
- Wiki revision:见本地镜像头
|
||||
|
||||
## 背景与目标
|
||||
|
||||
Sense 原规则要求密码至少 12 个字符。负责人在收到生产安全风险提示后,明确确认 demo 与生产全部调整为最少 6 个字符;大小写字母、数字和不得包含用户名的复杂度规则保持不变。
|
||||
|
||||
## 最终方案
|
||||
|
||||
- 后端统一密码校验最短长度由 12 改为 6,bootstrap 和管理员创建用户继续复用同一校验入口。
|
||||
- 新增 6 字符通过、5 字符拒绝及大小写/数字/用户名约束的表驱动测试。
|
||||
- 前端新用户表单最小长度和中文提示同步为 6。
|
||||
- Wiki 记录全模式稳定规则和管理员交付说明。
|
||||
- 重新生成 Windows amd64 前后端 ZIP,并用包内程序执行 6 位密码初始化和登录。
|
||||
|
||||
## 修改文件
|
||||
|
||||
- `Sense/server/app/sense/identity/password.go`:最短长度改为 6。
|
||||
- `Sense/server/app/sense/identity/password_test.go`:长度和复杂度边界测试。
|
||||
- `Sense/ui/src/views/sense/identity/Users.vue`:前端最小长度及提示。
|
||||
- `docs/03-business-rules-and-glossary.md`、`docs/delivery/README.md`:Wiki-first 规则镜像。
|
||||
- `wiki-docs.json`、`docs/task/40-Sense全模式密码最短6位.md`:任务归档。
|
||||
|
||||
## 验收结果
|
||||
|
||||
| 验收标准 | 结果 |
|
||||
|---|---|
|
||||
| 6 字符合规密码通过统一校验 | 通过 |
|
||||
| 5 字符密码被拒绝 | 通过 |
|
||||
| 大写、小写、数字和用户名限制保留 | 通过 |
|
||||
| 前后端提示一致 | 通过 |
|
||||
| Windows ZIP 重新生成并启动 | 通过 |
|
||||
| 不生成默认账号、密码或秘密 | 通过 |
|
||||
|
||||
## 测试
|
||||
|
||||
- `go test ./app/sense/identity/...`:通过。
|
||||
- `go test ./...`:Sense 全包通过。
|
||||
- `corepack pnpm@9.15.1 lint`:0 error;存在既有格式 warning。
|
||||
- `cmd /c Sense\scripts\package-windows.bat`:通过;前端仅有既有 vendor bundle 体积警告。
|
||||
- 包内接口验证:使用 `Abc123` 初始化返回 201,登录返回 200。
|
||||
- ZIP:7,281,361 bytes;SHA-256 `9A623C7B1E0F9F925DB7BBE3B5FFBE81D3A6B5BA5819F741D0AEC5681583D63C`。
|
||||
- Harness:31 项测试和 strict 检查通过;Wiki 镜像检查通过。
|
||||
- **未验证部分**:未在真实 PostgreSQL 环境执行首次管理员初始化,未由目标管理员人工验收;生产采用 6 字符密码的安全风险为用户明确接受的产品决策。
|
||||
|
||||
## 遗留问题
|
||||
|
||||
- 6 字符最短长度显著弱于原 12 字符规则;本工单未增加 MFA、登录限速或外部身份提供者。
|
||||
|
||||
## 相关提交
|
||||
|
||||
- `f841ef1` feat: lower Sense password minimum to six characters (#40)
|
||||
- `2d501ea` docs: record Sense six-character password policy (#40)
|
||||
- `4c4b114` docs: create task 40 acceptance archive (#40)
|
||||
@@ -115,6 +115,10 @@
|
||||
{
|
||||
"page": "Task-37-Sense-Windows前后端一键打包",
|
||||
"path": "docs/task/37-Sense-Windows前后端一键打包.md"
|
||||
},
|
||||
{
|
||||
"page": "Task-40-Sense全模式密码最短6位",
|
||||
"path": "docs/task/40-Sense全模式密码最短6位.md"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user