# Ubuntu User Management API ## 基本信息 - 服务地址示例: `http://127.0.0.1:8000` - API 版本: `1.0.0` - 文档地址: `/docs` - OpenAPI 地址: `/openapi.json` - 请求与响应格式: `application/json` ## 鉴权 所有业务接口都需要 Bearer Token。 请求头: ```http Authorization: Bearer ``` `TOKEN` 来自 `.env`: ```env TOKEN=your-token SERVER_NAME=user-manage-api ``` 鉴权失败响应: ```json { "detail": { "code": "unauthorized", "message": "Invalid bearer token." } } ``` ## 通用错误格式 业务错误: ```json { "code": "not_found", "message": "user not found" } ``` 参数错误: ```json { "code": "invalid_parameter", "message": "..." } ``` 常见错误码: | HTTP 状态码 | code | 描述 | | --- | --- | --- | | 400 | `invalid_parameter` | 请求参数格式或校验失败 | | 400 | `invalid_home_dir` | `home_dir` 不在 `HOME_BASE_DIR` 下 | | 401 | `unauthorized` | 未提供 token 或 token 不正确 | | 404 | `not_found` | 用户或用户组不存在,或被可见性规则隐藏 | | 409 | `resource_conflict` | 用户或用户组已存在 | | 422 | `precondition_failed` | 前置条件不满足,例如用户组仍有成员 | | 423 | `user_locked` | 用户已锁定,只允许查看,不允许修改 | | 500 | `system_command_error` | 系统命令执行失败 | | 503 | `system_timeout` | 系统命令超时 | | 503 | `system_permission_denied` | 系统命令权限不足 | ## 可见性规则 用户和用户组会受 `.env` 中的白名单、黑名单和 UID/GID 范围限制。 优先级: ```text 白名单 > 黑名单 > UID/GID 范围 ``` 相关配置: ```env WHITELIST_USERS= WHITELIST_GROUPS= HIDDEN_USERS=root,daemon,nobody HIDDEN_GROUPS=root,daemon,nogroup LOCKED_USERS= USER_UID_MIN=1000 USER_UID_MAX=60000 GROUP_GID_MIN=1000 GROUP_GID_MAX=60000 ``` 说明: - 白名单中的用户/用户组始终可见并允许操作。 - 黑名单中的用户/用户组会被隐藏并禁止操作,除非同时在白名单中。 - 不在白名单和黑名单时,用户按 UID 范围判断,用户组按 GID 范围判断。 - 被隐藏的用户或用户组对 API 表现为 `404 not_found`。 - `LOCKED_USERS` 中的用户可以查看,但不能创建同名用户、删除、改密码、添加用户组或移除用户组。 ## Home 目录规则 相关配置: ```env HOME_BASE_DIR=/home LINK_HOME_DIR= ``` 创建用户时: - `home_dir` 为空时,默认使用 `HOME_BASE_DIR/username`。 - `home_dir` 不为空时,必须位于 `HOME_BASE_DIR` 下。 - `LINK_HOME_DIR` 为空时,用户目录直接创建在 `HOME_BASE_DIR` 下。 - `LINK_HOME_DIR` 不为空时,实际目录创建在 `LINK_HOME_DIR/username`,并在 `HOME_BASE_DIR/username` 创建软链接。 删除用户时: - 会删除用户账号。 - 如果用户 home 是软链接,则删除该软链接。 - 如果用户 home 是普通目录,不会删除目录内容。 ## 数据模型 ### UserCreateRequest | 字段 | 类型 | 必填 | 默认值 | 描述 | | --- | --- | --- | --- | --- | | `username` | string | 是 | - | 用户名。格式: `^[a-z_][a-z0-9_-]{0,31}$` | | `password_hash` | string | 是 | - | 预先生成的 Linux 密码 hash,长度 10 到 512 | | `primary_group` | string/null | 否 | `null` | 主用户组。格式同用户组名 | | `groups` | string[] | 否 | `[]` | 附加用户组,会自动去重 | | `shell` | string | 否 | `/bin/bash` | 登录 shell | | `home_dir` | string/null | 否 | `null` | 用户 home 路径,必须在 `HOME_BASE_DIR` 下 | ### UserSummary | 字段 | 类型 | 描述 | | --- | --- | --- | | `username` | string | 用户名 | | `uid` | integer | 用户 UID | | `gid` | integer | 用户主 GID | | `home_dir` | string | 用户 home 路径 | | `shell` | string | 登录 shell | ### GroupCreateRequest | 字段 | 类型 | 必填 | 描述 | | --- | --- | --- | --- | | `groupname` | string | 是 | 用户组名。格式: `^[a-z_][a-z0-9_-]{0,31}$` | ### GroupSummary | 字段 | 类型 | 描述 | | --- | --- | --- | | `groupname` | string | 用户组名 | | `gid` | integer | 用户组 GID | | `members` | string[] | 用户组成员 | ### UserGroupsUpdateRequest | 字段 | 类型 | 必填 | 默认值 | 描述 | | --- | --- | --- | --- | --- | | `groups` | string[] | 是 | - | 用户组列表,至少 1 个,会自动去重 | | `mode` | string | 否 | `append` | `append` 表示追加,`replace` 表示替换全部附加组 | ### UserPasswordUpdateRequest | 字段 | 类型 | 必填 | 描述 | | --- | --- | --- | --- | | `password_hash` | string | 是 | 新密码的 Linux hash,长度 10 到 512。API 不接收明文密码 | ### ApiResponse | 字段 | 类型 | 描述 | | --- | --- | --- | | `status` | string | 固定为 `ok` | | `message` | string | 操作结果描述 | ## API 列表 ### 健康检查 ```http GET /health ``` 描述: 返回服务器名称和在线状态。服务器名称来自 `.env` 中的 `SERVER_NAME`。 成功响应: ```json { "server_name": "user-manage-api", "status": "online" } ``` 字段说明: | 字段 | 类型 | 描述 | | --- | --- | --- | | `server_name` | string | 服务器名称,由 `SERVER_NAME` 配置 | | `status` | string | 固定为 `online` | ### 创建用户 ```http POST /users ``` 描述: 创建系统用户。密码必须由调用方提前生成 hash,API 不处理明文密码。 请求体: ```json { "username": "alice", "password_hash": "$6$salt$hash", "primary_group": null, "groups": ["dev"], "shell": "/bin/bash", "home_dir": "/home/alice" } ``` 最小请求体: ```json { "username": "alice", "password_hash": "$6$salt$hash" } ``` 成功响应: ```json { "status": "ok", "message": "User created." } ``` 注意: - `username` 在黑名单中且不在白名单中时禁止创建。 - `primary_group` 和 `groups` 中的用户组必须存在且可见。 - `home_dir` 必须在 `HOME_BASE_DIR` 下。 - 启用 `LINK_HOME_DIR` 后,账号 home 仍为 `HOME_BASE_DIR/username`,实际目录位于 `LINK_HOME_DIR/username`。 ### 删除用户 ```http DELETE /users/{username} ``` 路径参数: | 参数 | 类型 | 描述 | | --- | --- | --- | | `username` | string | 要删除的用户名 | 成功响应: ```json { "status": "ok", "message": "User deleted." } ``` 注意: - 用户不存在或被隐藏时返回 `404`。 - 用户在 `LOCKED_USERS` 中时返回 `423 user_locked`。 - 删除账号后,如果 home 是软链接,会删除该软链接。 - 如果 home 是普通目录,不会删除目录内容。 ### 修改用户密码 ```http PATCH /users/{username}/password ``` 路径参数: | 参数 | 类型 | 描述 | | --- | --- | --- | | `username` | string | 要修改密码的用户名 | 请求体: ```json { "password_hash": "$6$rounds=5000$salt$hash" } ``` 成功响应: ```json { "status": "ok", "message": "User password updated." } ``` 注意: - `password_hash` 必须是调用方提前生成的 Linux 密码 hash。 - 用户不存在或被隐藏时返回 `404`。 - 用户在 `LOCKED_USERS` 中时返回 `423 user_locked`。 ### 获取用户列表 ```http GET /users ``` 描述: 返回可见用户列表。会应用白名单、黑名单和 UID 范围规则。 成功响应: ```json [ { "username": "alice", "uid": 1000, "gid": 1000, "home_dir": "/home/alice", "shell": "/bin/bash" } ] ``` ### 获取用户详情 ```http GET /users/{username} ``` 路径参数: | 参数 | 类型 | 描述 | | --- | --- | --- | | `username` | string | 用户名 | 成功响应: ```json { "username": "alice", "uid": 1000, "gid": 1000, "home_dir": "/home/alice", "shell": "/bin/bash" } ``` ### 创建用户组 ```http POST /groups ``` 请求体: ```json { "groupname": "dev" } ``` 成功响应: ```json { "status": "ok", "message": "Group created." } ``` 注意: - `groupname` 在黑名单中且不在白名单中时禁止创建。 ### 删除用户组 ```http DELETE /groups/{groupname} ``` 路径参数: | 参数 | 类型 | 描述 | | --- | --- | --- | | `groupname` | string | 要删除的用户组名 | 成功响应: ```json { "status": "ok", "message": "Group deleted." } ``` 注意: - 用户组不存在或被隐藏时返回 `404`。 - 用户组仍有成员时返回 `422 precondition_failed`。 ### 获取用户组列表 ```http GET /groups ``` 描述: 返回可见用户组列表。会应用白名单、黑名单和 GID 范围规则。 成功响应: ```json [ { "groupname": "dev", "gid": 1000, "members": ["alice"] } ] ``` ### 获取用户组详情 ```http GET /groups/{groupname} ``` 路径参数: | 参数 | 类型 | 描述 | | --- | --- | --- | | `groupname` | string | 用户组名 | 成功响应: ```json { "groupname": "dev", "gid": 1000, "members": ["alice"] } ``` ### 添加或替换用户附加组 ```http POST /users/{username}/groups ``` 路径参数: | 参数 | 类型 | 描述 | | --- | --- | --- | | `username` | string | 用户名 | 请求体: ```json { "groups": ["dev", "ops"], "mode": "append" } ``` 参数说明: | 字段 | 类型 | 描述 | | --- | --- | --- | | `groups` | string[] | 要添加或替换的用户组列表 | | `mode` | string | `append` 追加用户组,`replace` 替换全部附加组 | 成功响应: ```json { "status": "ok", "message": "User groups updated." } ``` 注意: - 用户不存在或被隐藏时返回 `404`。 - 用户在 `LOCKED_USERS` 中时返回 `423 user_locked`。 - 目标用户组不存在或被隐藏时返回 `404`。 ### 移除用户附加组 ```http DELETE /users/{username}/groups ``` 路径参数: | 参数 | 类型 | 描述 | | --- | --- | --- | | `username` | string | 用户名 | 请求体: ```json { "groups": ["dev"], "mode": "append" } ``` 说明: `mode` 字段会被接收,但删除操作只使用 `groups`。 成功响应: ```json { "status": "ok", "message": "User groups removed." } ``` 注意: - 用户不存在或被隐藏时返回 `404`。 - 用户在 `LOCKED_USERS` 中时返回 `423 user_locked`。 ### 获取用户所属用户组 ```http GET /users/{username}/groups ``` 路径参数: | 参数 | 类型 | 描述 | | --- | --- | --- | | `username` | string | 用户名 | 成功响应: ```json { "username": "alice", "groups": ["dev", "ops"] } ``` 说明: 返回的 `groups` 会过滤掉不可见用户组。 ## curl 示例 ```bash curl -X GET 'http://127.0.0.1:8000/users' \ -H 'Authorization: Bearer ' ``` ```bash curl -X POST 'http://127.0.0.1:8000/users' \ -H 'Authorization: Bearer ' \ -H 'Content-Type: application/json' \ -d '{ "username": "alice", "password_hash": "$6$rounds=5000$salt$hash", "shell": "/bin/bash" }' ```