ClouisleClouisle

用户管理

管理用户账户、激活状态、密码策略与 TOTP

用户管理在管理台 Users(/users)页面,按动作区分权限:查看 admin:user:read、创建 admin:user:create、修改/激活/停用/密码策略 admin:user:update、删除 admin:user:delete。内置 Admin 角色持有这四项全部权限。

本页列出每个动作的真实端点、校验规则与失败后的表现。用户角色如何影响权限见角色与权限。

列表与筛选

GET /api/v1/admin/users(admin:user:read)返回分页用户列表,参数:

参数说明
page / page_size分页,默认 page=1、page_size=20
search按用户名或邮箱模糊匹配(不区分大小写)
status可多选:active、inactive、pending
role按全局角色名过滤
exclude_user_id排除指定用户 ID(用于选择器等场景)

状态定义:active = is_active=true;inactive = is_active=false 且 approval_status=approved;pending = 待审批(approval_status=pending,is_active=false)。

顶部统计来自 GET /api/v1/admin/users/stats(admin:user:read),返回 total / active / inactive / pending。列表默认不显示登录次数、失败登录次数、最后改密时间——这些字段接口不返回。

创建用户

POST /api/v1/admin/users(admin:user:create):

  1. 点击 Create User。
  2. 填写 Username(全局唯一)、Email(全局唯一,需为合法邮箱)、Password、Active 开关(is_active)。
  3. 保存。

后端行为与校验:

情况结果
用户名已存在user_with_username_exists
邮箱已存在user_with_email_exists
未提供 locale回退到站点设置 default_language(默认 en)
—新用户 approval_status 强制写入 approved

创建表单不接受 roles:新用户没有任何全局角色,创建后必须单独指派,否则只能看到公开资源、无法在团队内操作。

批量导入 / SSO 自动创建

未实现 / Roadmap。 没有 CSV/JSON/Excel 用户导入,只能逐个创建(POST /api/v1/admin/users),或在 SSO 首次登录时自动创建。

SSO 自动创建由站点设置控制(Site Settings → SSO/Security):

设置说明
sso_auto_create_users开启后 SSO 首次登录自动建号
default_role_id新用户默认全局角色,首次初始化指向 Viewer
default_team_id + default_team_role默认团队与成员角色,default_team_role 只接受 viewer/member/admin,缺省 member;owner 永不自动分配
sso_match_by_email按邮箱匹配已有账户
sso_require_approval新账户需审批(approval_status=pending)

未实现 / Roadmap:SSO 自动创建没有邮箱域白名单限制。

查看用户详情

点击用户打开详情/编辑面板(GET /api/v1/admin/users/{user_id},admin:user:read)。可见字段:

  • 身份:username、email、is_active、approval_status、is_superuser、auth_source(local / sso)、email_verified
  • 偏好:locale、avatar_url
  • 时间:created_at、last_login
  • 密码状态:force_password_change、password_expiration_exempt(列表里显示为密码状态徽标)
  • 授权:roles(全局角色数组)
  • SSO:sso_connections(提供商、外部账号、首次/最后登录),有 admin:sso:update 时可断开连接

未实现 / Roadmap:用户管理内没有单用户活动视图、登录历史、活跃会话列表或会话撤销。账户锁定由全局登录策略 max_login_attempts / lockout_duration_minutes 强制执行;用户行为需到 Audit Logs 按用户筛选查看。

编辑用户

PUT /api/v1/admin/users/{user_id}(admin:user:update)。可提交字段:

字段说明
email改为新邮箱
is_active激活/停用开关
roles全局角色名数组,整体替换
password可选。提交即改密(需通过密码强度校验,失败返回 password_validation_failed,data.errors.password 带具体原因)
avatar_url / locale头像与语言偏好

username 不可修改:UserUpdate schema 不含该字段,前端编辑表单也不提供用户名输入框。写错用户名只能删除重建。

角色改动的保护规则

roles 是整体替换(先清空再写入,未列出的角色会丢失;匹配不到的角色名被忽略)。若目标用户仍是某些团队的 owner/admin,而新角色集不再包含 team:manage(或 *),请求返回 403 operation_not_permitted(permission: team:manage)。先降级团队角色,再摘全局角色,否则顺序反了会被挡住。

提交密码时后端会向该用户发送 user.password_reset 通知。

账户状态

操作端点权限说明
激活POST /api/v1/admin/users/{user_id}/activateadmin:user:updateis_active=true 且 approval_status=approved;已是激活状态返回 user_already_active
停用POST /api/v1/admin/users/{user_id}/deactivateadmin:user:updateis_active=false、approval_status=approved;超管被拒(cannot_deactivate_superuser);已停用返回 user_already_inactive

停用的实际效果:

  • 无法登录:JWT 与 API Key 两条认证路径都会因为 is_active=false 拒绝(401 inactive_user,待审批用户是 pending_approval_user)。
  • 使用他名下 API Key 的集成立即失败——Key 本身不会被改写,但认证时因用户已停用而拒绝。
  • 资源、团队归属、会话全部保留;重新激活即可恢复。

激活/停用都会给用户发送 user.activated / user.deactivated 通知,并写审计日志(activate_user / deactivate_user)。

删除用户

DELETE /api/v1/admin/users/{user_id}(admin:user:delete)。唯一硬性拦截:is_superuser=true 的账户返回 cannot_delete_superuser。前端删除对话框要求输入用户名确认,并列出影响范围。

删除影响(按模型外键规则,已核对 models/*.py):

会被删除(CASCADE)会被置空/保留(SET_NULL)
账户本身、密码历史、通知与已读记录他创建的 Agent / 知识库 / 文档 / 工具 / Skill(created_by 置空并保留)
个人对话及其消息、Agent 运行记录他拥有的团队(Team.owner 置空,团队本身保留)
他名下的 API Key、个人记忆审计日志(合规用途,不随账户删除)
全部团队成员关系、作用域角色记录团队内的共享资源与其他成员

删除团队 owner 会让团队失去 owner

TeamMember 随用户级联删除,因此删除某个团队的 owner 会同时删掉他的 owner 成员关系,团队 owner 字段被置空,该团队此后没有 owner——只有超管能改成员角色或补授所有权。要移除团队 owner,请先在团队里转让所有权,再删除账户。

密码与密码过期

没有「重置为临时密码」或「从管理台发送重置邮件」的流程。管理员用下面这组按用户操作配合全局密码策略:

操作端点权限行为
强制下次登录改密POST /api/v1/admin/users/{user_id}/force-password-changeadmin:user:updateforce_password_change=true,并发送高优先级通知
重置过期计时POST /api/v1/admin/users/{user_id}/reset-password-expirationadmin:user:updatepassword_changed_at=now,按策略重算 password_expires_at,清空到期提醒时间
设置/取消免过期POST /api/v1/admin/users/{user_id}/exempt-password-expiration,请求体 {"exempt": true/false}admin:user:update写入 password_expiration_exempt;exempt=true 时同时清除 force_password_change
批量强制改密POST /api/v1/admin/users/bulk-force-password-change,请求体 {"user_ids": [...]}admin:user:update逐个置位并通知;返回 {"count": n};空数组 no_users_selected,全部不存在 no_users_found
密码过期概览GET /api/v1/admin/users/password-expiration-statsadmin:user:read返回 total_users/expired_count/expiring_soon_count/force_change_count/exempt_count;若站点设置 password_expiration_enabled=false,全部返回 0
过期/即将过期清单GET /api/v1/admin/users/expiring-passwordsadmin:user:read分页(page、page_size 最大 100),filter 取 all/expired/expiring/force_change;「即将过期」窗口由 password_expiration_warning_days(默认 7 天)决定

前端只在详情页/行内菜单展示这些操作,且仅当 auth_source=local(SSO 用户没有本地密码);全局策略配置在 Site Settings → Security。

TOTP(双因素)

能力端点权限界面
TOTP 采用率统计GET /api/v1/admin/totp/statsadmin:dashboard:access管理台 Dashboard 的 TOTP 卡片(totp_enabled / total_users / adoption_rate)
查看某用户 TOTP 状态GET /api/v1/admin/totp/users/{user_id}/status超管无界面,仅 API
禁用某用户 TOTPPOST /api/v1/admin/totp/users/{user_id}/disable超管无界面,仅 API

用户自助的开启/关闭/备份码在个人设置里完成(见登录与账户)。

# 需要超管 Token
curl "https://your-domain.com/api/v1/admin/totp/users/$USER_ID/status" \
  -H "Authorization: Bearer $ADMIN_TOKEN"

curl -X POST "https://your-domain.com/api/v1/admin/totp/users/$USER_ID/disable" \
  -H "Authorization: Bearer $ADMIN_TOKEN"

用户管理界面没有按用户开关 TOTP 的入口,也没有「强制某人启用 2FA」的开关;现有能力是统计数据 + 超管 API 兜底禁用(例如用户丢失验证器时)。

批量操作

用户列表勾选多人后弹出底部工具条。注意其中多项是前端循环调用单用户接口实现的,没有对应批量端点:

操作实现要求
发通知POST /api/v1/admin/notifications(逐个用户)admin:notification:create
激活循环 POST .../{user_id}/activateadmin:user:update
停用循环 POST .../{user_id}/deactivateadmin:user:update
删除循环 DELETE .../{user_id}admin:user:delete
强制改密POST /api/v1/admin/users/bulk-force-password-change(真批量)admin:user:update
授予 / 取消密码免过期循环 POST .../{user_id}/exempt-password-expirationadmin:user:update

因为没有真正的批量端点,单条失败不会回滚其余条目;返回的 toast 计数可能与实际成功数不一致,涉及权限/状态冲突的用户请核对后再重试。

未实现 / Roadmap:没有批量加入/移出团队、批量导出、CSV 导入/导出。

发送邮件

POST /api/v1/admin/users/send-email,请求体 {"user_ids": [...], "subject": "...", "content": "..."},需要 admin:user:update。响应为 {"sent_count": n, "skipped_count": n, "total": n}。

限制(超过即报错,不会部分发送):

限制值错误
SMTP 未启用(smtp_enabled=false)—smtp_not_configured
单管理员每小时发信量100email_rate_limit_exceeded(data.limit=100、data.period=hour)
单收件人每天收信量5该收件人被跳过并计入 skipped_count
本次请求人数超过管理员剩余额度—email_quota_insufficient(data.requested / data.remaining)

用户角色

全局角色(可多选,roles)决定系统级与管理台能力,团队角色决定团队内级别。内置 5 个角色与权限集见角色与权限:

角色大致能力
Super Admin*,绕过一切检查
Admin管理台读写 + 全团队资源权限
Team AdminMember + 团队设置与成员管理
Member团队内创建/编辑/运行资源
Viewer只读 + 使用,默认角色

团队角色(owner/admin/member/viewer)在团队页面维护,不在用户详情里改:用户详情只读展示团队归属。

最佳实践

✅ 推荐:

  • 定期复核用户列表,及时停用离职人员(停用即可立即阻断登录与 API Key)
  • 创建后立刻指派最小必要的全局角色
  • 特权账户强制启用 2FA,并为其设置 password_expiration_exempt 之外的正常轮换策略
  • 用 expiring-passwords 清单提前处理即将过期账户,而不是等锁定后救火
  • 停用、删除、改角色等操作前后留痕(审计日志自带)

❌ 避免:

  • 多人共用管理员账户(审计日志无法区分责任人)
  • 直接删除团队 owner 的账户(团队会变成无 owner 状态)
  • 用 PUT /admin/users/{id} 一次性替换角色集却漏掉某角色
  • 依赖「前端隐藏按钮」做权限控制——接口是独立校验的

故障排除

无法创建用户

  1. 检查用户名、邮箱是否已被占用(user_with_username_exists / user_with_email_exists)。
  2. 检查邮箱格式是否合法。
  3. 检查调用者是否持有 admin:user:create。

用户无法登录

  1. 确认 is_active=true(停用或待审批都会 401)。
  2. 确认密码正确;必要时先强制改密或直接改密。
  3. 确认账户未被登录策略锁定(max_login_attempts / lockout_duration_minutes)。
  4. 确认 TOTP 状态;用户丢失验证器时由超管调用禁用 TOTP 接口(无 UI)。
  5. 到 Audit Logs 按用户排查异常登录。

无法删除用户

  • 目标是超管 → cannot_delete_superuser(先摘掉超管标记或改用停用)。
  • 目标是团队 owner → 后端不会阻止删除,但团队会失去 owner;先在团队里转让所有权再删除。
  • 其他情况删除都会成功,务必确认上述级联清单(对话、API Key、成员关系会一并消失)。

改角色报 403

用户仍是某些团队的 owner/admin,而新角色集里没有 team:manage。先到团队里降级他的成员角色,再改全局角色。

API 端点参考

端点方法权限说明
/api/v1/admin/usersGETadmin:user:read分页列表(page/page_size/status/search/role)
/api/v1/admin/users/statsGETadmin:user:read总数/激活/停用/待审批统计
/api/v1/admin/usersPOSTadmin:user:create创建用户
/api/v1/admin/users/{user_id}GETadmin:user:read用户详情
/api/v1/admin/users/{user_id}PUTadmin:user:update改邮箱/激活状态/角色/密码
/api/v1/admin/users/{user_id}DELETEadmin:user:delete删除用户
/api/v1/admin/users/{user_id}/activatePOSTadmin:user:update激活
/api/v1/admin/users/{user_id}/deactivatePOSTadmin:user:update停用
/api/v1/admin/users/{user_id}/force-password-changePOSTadmin:user:update强制下次登录改密
/api/v1/admin/users/{user_id}/reset-password-expirationPOSTadmin:user:update重置过期计时
/api/v1/admin/users/{user_id}/exempt-password-expirationPOSTadmin:user:update设置/取消免过期({"exempt": bool})
/api/v1/admin/users/bulk-force-password-changePOSTadmin:user:update批量强制改密
/api/v1/admin/users/password-expiration-statsGETadmin:user:read密码过期概览
/api/v1/admin/users/expiring-passwordsGETadmin:user:read过期/即将过期清单
/api/v1/admin/users/send-emailPOSTadmin:user:update批量发送邮件
/api/v1/admin/totp/statsGETadmin:dashboard:accessTOTP 采用率
/api/v1/admin/totp/users/{user_id}/statusGET超管查看用户 TOTP 状态
/api/v1/admin/totp/users/{user_id}/disablePOST超管禁用用户 TOTP

/users/{user_id}/permissions、/users/{user_id}/permissions/check 一类用户级权限端点不存在;权限只能通过全局角色与团队成员关系获得。


参见:

这篇文章对你有帮助吗?

本页目录