用户管理(Admin)
admin-create-user、admin-reset-password、manage-user-role 三个管理后台函数的鉴权、操作与审计日志
本页面描述管理中心(Dashboard)使用的三个用户管理 Edge Function。它们共享相同的鉴权模型和审计日志机制,仅供 admin 角色调用。
通用机制
鉴权模型
三个函数使用相同的两阶段鉴权:
JWT 校验(Supabase 网关层):verify_jwt: true,拦截无效或过期的 JWT
角色检查(函数层):通过 supabase.auth.getUser() 获取调用者信息,检查 app_metadata.role === 'admin',非 admin 返回 403
角色信息存储在 auth.users.app_metadata.role 中,取值为 admin / editor / user。app_metadata 只能通过 Admin API 修改,用户自身无法篡改。
审计日志
每次操作成功后,函数会向 admin_logs 表写入一条记录,包含操作者、目标用户、操作类型、客户端 IP 和详情。即使日志写入失败,操作本身不会回滚(已完成),但会输出 CRITICAL 级别日志。
| action_type | 对应函数 | 说明 |
|---|---|---|
USER_CREATE | admin-create-user | 创建新用户 |
RESET_PASSWORD | admin-reset-password | 重置密码 |
USER_PROMOTE | manage-user-role | 提升为 editor |
USER_DEMOTE | manage-user-role | 降级为 user |
双客户端模式
三个函数都创建了两个 Supabase 客户端:
- Client A(ANON_KEY + 用户 JWT):用于验证调用者身份
- Client B(SERVICE_ROLE_KEY):用于执行需要 Admin API 权限的操作(创建用户、修改密码、更新
app_metadata)
admin-create-user
在管理中心创建新用户账号。
| 属性 | 值 |
|---|---|
| 方法 | POST |
| JWT 校验 | 是 |
| CORS | 支持 |
| 调用方 | Dashboard 管理中心 |
请求参数
Prop
Type
此函数只能创建 user 或 editor 角色。不能通过此函数创建 admin——admin 账号需直接操作数据库。
处理流程
参数校验:邮箱格式、密码长度 ≥ 6、角色为 user / editor、理由 ≥ 5 字符
调用 Admin API:supabaseAdmin.auth.admin.createUser() 创建用户,设置 email_confirm: true(跳过邮箱验证),将 role 写入 app_metadata,display_name 写入 user_metadata
邮箱冲突处理:如果邮箱已注册,返回 409 Conflict
写入审计日志:记录操作者、新用户 ID、角色、创建理由
响应示例
{
"message": "User created successfully",
"user": {
"id": "uuid",
"email": "newuser@example.com",
"role": "editor",
"display_name": "新编辑"
}
}审计日志 details
{
"email": "newuser@example.com",
"role": "editor",
"display_name": "新编辑",
"reason": "新招的漫画编辑,负责日漫区",
"created_by_admin": true
}admin-reset-password
管理员为目标用户重置密码。
| 属性 | 值 |
|---|---|
| 方法 | POST |
| JWT 校验 | 是 |
| CORS | 支持 |
| 调用方 | Dashboard 管理中心 |
请求参数
Prop
Type
处理流程
鉴权:验证调用者为 admin
修改密码:supabaseAdmin.auth.admin.updateUserById(target_user_id, { password })
写入审计日志:记录操作者和目标用户(不记录密码明文)
响应示例
{ "message": "Password updated successfully" }此函数不检查目标用户的角色——admin 可以重置任何人的密码,包括其他 admin。使用时需谨慎。
manage-user-role
提升或降级用户角色(user ↔ editor)。
| 属性 | 值 |
|---|---|
| 方法 | POST |
| JWT 校验 | 是 |
| CORS | 支持 |
| 调用方 | Dashboard 管理中心 |
请求参数
Prop
Type
处理流程
鉴权:验证调用者为 admin
获取目标用户:通过 admin.getUserById() 查询目标用户信息
保护检查:如果目标用户是 admin,返回 403——不允许通过此函数修改其他 admin 的角色
更新角色:admin.updateUserById() 将 app_metadata.role 设为 editor(promote)或 user(demote)
写入审计日志:记录变更前后的角色、操作类型和理由
角色变更规则
promote: user → editor (获得内容编辑权限)
demote: editor → user (移除编辑权限)不能将用户提升为 admin,也不能降级 admin。admin 角色的管理需直接操作数据库。
响应示例
{
"message": "User promoted successfully",
"new_role": "editor",
"user_id": "target-uuid"
}审计日志 details
{
"previous_role": "user",
"new_role": "editor",
"action_requested": "promote",
"note": "提升为编辑 - 理由: 负责韩漫区内容上传"
}角色体系
三种角色的权限层级:
| 角色 | 来源 | 能力 |
|---|---|---|
user | 默认注册 | 普通用户,阅读漫画、发表评论 |
editor | admin 指定 | 编辑权限,管理漫画内容(上传、编辑、排序) |
admin | 直接操作数据库 | 全部权限,包括用户管理、系统配置 |
角色存储在 auth.users.app_metadata.role,被 RLS 策略中的 is_admin() 和 is_admin_or_editor() RPC 函数引用。
相关数据表
admin_logs
Prop
Type
Secrets 依赖
| Secret | 说明 |
|---|---|
SUPABASE_URL | 系统自带 |
SUPABASE_ANON_KEY | 系统自带,用于验证调用者身份 |
SUPABASE_SERVICE_ROLE_KEY | 执行 Admin API 操作(创建用户、修改密码、更新 metadata) |
安全注意事项
- 所有操作均需 admin 角色,非 admin 调用一律返回 403
- admin-reset-password 没有角色保护:admin 可以重置任何人的密码(包括其他 admin),如需限制应在函数层添加检查
- manage-user-role 有 admin 保护:不允许通过此函数修改 admin 角色,防止 admin 之间互相降权
- 理由必填:admin-create-user 和 manage-user-role 要求提供操作理由(≥ 5 字符),确保审计可追溯
- IP 记录:从
x-forwarded-for头提取客户端 IP,可能经过代理,不完全可靠但可作为参考