Skip to content

当前用户

获取当前认证用户的身份信息,以及管理「我的凭证」(API Key、Agent Token、OAuth 授权)。

源码: apps/backend/src/routes/my.ts

GET /my

返回当前认证方式及其关联信息。

认证方式

JWT Token / API Key / Agent Token(combinedAuth

请求参数

响应格式

状态码: 200

响应内容取决于认证方式:

JWT 认证响应

json
{
  "method": "jwt",
  "userId": "uuid",
  "email": "user@example.com",
  "metadata": {
    "display_name": "用户名",
    "avatar_url": "https://..."
  }
}
字段类型说明
methodstring固定值 "jwt"
userIdstring用户 UUID
emailstring用户邮箱
metadataobject用户元数据(user_metadata

API Key 认证响应

json
{
  "method": "api-key",
  "userId": "uuid",
  "teamId": "uuid",
  "apiKeyId": "uuid"
}
字段类型说明
methodstring固定值 "api-key"
userIdstringAPI Key 创建者的用户 ID
teamIdstringAPI Key 所属团队 ID
apiKeyIdstringAPI Key 记录 ID

Agent Token 认证响应

json
{
  "method": "agent",
  "userId": "uuid",
  "teamId": "uuid",
  "bindingId": "uuid"
}
字段类型说明
methodstring固定值 "agent"
userIdstringAgent 关联的用户 ID
teamIdstringAgent 所属团队 ID
bindingIdstringagent_bindings 记录 ID

Agent Token 需在其权限组中显式授予 GET /my 访问权限才会到达本端点;未授权时由 combinedAuthcheckTokenPermission 拦截。

Schedule 认证响应

json
{
  "method": "schedule",
  "scheduleId": "uuid",
  "teamId": "uuid",
  "deploymentId": "uuid"
}
字段类型说明
methodstring固定值 "schedule"
scheduleIdstring定时任务 ID
teamIdstring所属团队 ID
deploymentIdstring目标部署 ID

请求示例

bash
# JWT 认证
curl -H "Authorization: Bearer YOUR_JWT_TOKEN" \
  https://block2-api.wainao.chat/my

# API Key 认证
curl -H "Authorization: Bearer wn-your-api-key" \
  https://block2-api.wainao.chat/my

# Agent Token 认证
curl -H "Authorization: Bearer wna-your-agent-token" \
  https://block2-api.wainao.chat/my

错误码

状态码错误说明
401Missing or invalid authorization header缺少认证信息
401Invalid API key / Invalid token认证失败
403Permission denied: ...Token 权限组不包含 GET /my

POST /my/default-project/ensure

幂等创建或返回当前用户的「个人默认项目」。移动端录音、硬件等个人默认数据先调用此端点拿到 project.id,再复用 POST /storage/:projectId/upload 上传。

认证方式

接受:

  • JWT Token
  • OAuth Access Token(wno-...),且 token scopes 必须覆盖 mobile:full

API Key、Agent Token、Schedule Token 即使认证有效,也会被子路由 guard 拒绝。OAuth 场景下,RPC 的 p_user_id 始终来自 auth.userId,不会读取 body/query 中的用户 ID。

请求体

json
{
  "lang": "zh-CN"
}
字段类型必填说明
langstring命名语言。缺省时使用 Accept-Language 首段,再按 X-Server-Mode 兜底。

响应格式

json
{
  "success": true,
  "data": {
    "team": {
      "id": "uuid",
      "slug": "team-slug",
      "name": "我的团队"
    },
    "project": {
      "id": "uuid",
      "team_id": "uuid",
      "slug": "personal-space",
      "name": "个人空间",
      "system_purpose": "personal_default"
    },
    "permissions": {
      "storage_write": true,
      "deletion_locked": true
    }
  }
}

行为说明

  • 幂等:同一用户重复调用返回同一个 active personal_default 项目。
  • 按需创建:不会在登录或 /auth/initialize 时预建。
  • 归属:项目落在用户本人拥有的 active team 下;不会落到别人邀请用户加入的协作团队。
  • 可见性:项目在 Web 项目列表可见,但不可删除、不可设为公开;项目内改名、编辑、上传仍可正常进行。
  • 存储:拿到 project.id 后,直接调用 POST /storage/{project.id}/upload

错误码

状态码错误说明
401Missing or invalid authorization header / Invalid token / Invalid or revoked OAuth token / OAuth token has expired缺少认证或 token 无效、过期、撤销
403insufficient_scopeOAuth token 有效,但 scope 不包含 mobile:full 对本路由的授权
403This endpoint only accepts JWT or OAuth authentication凭证有效但不是 JWT/OAuth(例如 API Key、Agent Token)
409personal_default_project_invalid_team既有 personal_default 项目挂在非本人 owned team 或已删除 team,需人工修复数据
500internal_errorRPC 调用失败或返回结构异常

GET /my/account-bindings

返回当前账号可用于登录/绑定管理的邮箱与手机号状态。微信自动生成的占位邮箱会被过滤,不会作为真实邮箱返回。

认证方式

接受 JWT Token,或带 mobile:full scope 的 OAuth Access Token(wno-...)。API Key、Agent Token、Schedule Token 不允许访问。

响应格式

json
{
  "success": true,
  "data": {
    "email": "user@example.com",
    "email_verified_at": "2026-06-30T00:00:00Z",
    "phone": "13800138000",
    "phone_verified_at": "2026-06-30T00:00:00Z"
  }
}

未绑定的字段返回 null


POST /my/phone/send-otp

已登录用户在绑定手机号前,向目标手机号发送绑定用短信验证码(purpose=bind)。

此端点定义在 apps/backend/src/routes/hardware-sales/phone-auth.tsphoneBindRoutes,挂载于 /my/phone。它与公开的 POST /auth/phone/send-otppurpose=login,未登录登录/注册用)相互独立:验证码按 purpose 隔离消费,绑定流程必须经此入口取码,否则校验恒为 invalid_code

认证方式

接受 JWT Token,或带 mobile:full scope 的 OAuth Access Token(wno-...)。API Key、Agent Token、Schedule Token 不允许访问。

请求体

json
{
  "phone": "13800138000"
}
字段类型必填说明
phonestring目标手机号

响应格式

状态码200

json
{
  "success": true,
  "message": "验证码已发送",
  "expiresIn": 300,
  "retryAfter": 60
}
字段类型说明
successboolean固定 true
messagestring提示文案
expiresInnumber验证码有效期(秒)
retryAfternumber再次发送的冷却时间(秒)

短信通道

短信由后端短信 Provider 工厂下发,凭据来源按优先级回落:后台「短信验证码服务」DB 凭证组(service_provider:aliyun-pnvs,已启用即权威)→ env 兜底(本地开发:ALIYUN_PNVS_*ALIYUN_SMS_*)→ Mock(仅开发/测试,不真实下发)

  • 后台凭证组已启用但配置不全 / endpoint 非法 / DB 读取异常时fail-closed(发码失败,绝不回落 env 或 mock 掩盖问题)。
  • 凭据均未配置时回落 Mock 并打印一次告警。
  • 管理员可通过 GET /admin/services/sms-credential-source 查看运行时实际生效的来源。

改后台凭据后,因 getGroupConfig 的 5 分钟 TTL,最长 5 分钟内生效,无需重启进程。

限流

  • 内存级 IP 限流:每 IP 每分钟最多 HW_PHONE_OTP_RATE_LIMIT_IP_PER_MINUTE 次(默认 10),命中返回 429。
  • 手机号冷却:同一手机号在冷却窗口内重复请求返回 429,并附 Retry-After 响应头。
  • IP 每小时限流:同一 IP 每小时发送次数超限返回 429,响应体为 error=rate_limited 且含 retryAfter 字段与 Retry-After 头(当前不透出具体 reason)。

错误码

状态码错误说明
400invalid_body请求体格式无效
400invalid_phone手机号格式无效
401unauthorized缺少有效登录身份
429rate_limited请求过于频繁(含 retryAfter 字段与 Retry-After 头)
502send_failed验证码下发失败
500internal_error服务暂时不可用

POST /my/phone/bind

使用 /my/phone/send-otp 获取的绑定验证码,将手机号绑定到当前账号。验证码与登录/注册短信验证码隔离,必须使用 purpose=bind 的验证码。

认证方式

接受 JWT Token,或带 mobile:full scope 的 OAuth Access Token(wno-...)。

请求体

json
{
  "phone": "13800138000",
  "code": "123456"
}

响应格式

json
{
  "success": true,
  "data": {
    "phone": "13800138000",
    "phoneToken": "..."
  }
}

错误码

状态码错误说明
400invalid_body / invalid_phone / invalid_code / code_expired请求体、手机号或验证码无效
401unauthorized缺少有效登录身份
409phone_taken该手机号已被其他账号绑定
429too_many_attempts验证码尝试次数过多
500internal_error服务暂时不可用

DELETE /my/phone

解绑当前账号手机号。如果解绑后账号没有其它可登录方式,返回 409 last_credential,防止用户锁死账号。

认证方式

接受 JWT Token,或带 mobile:full scope 的 OAuth Access Token(wno-...)。

响应格式

json
{
  "success": true
}

POST /my/email/send-otp

向目标邮箱发送账号绑定验证码。此验证码写入独立的 account_binding_email_otp_codes 表,不复用登录 OTP。

认证方式

接受 JWT Token,或带 mobile:full scope 的 OAuth Access Token(wno-...)。

请求体

json
{
  "email": "user@example.com",
  "lang": "zh-CN"
}

lang 可选;缺省时读取 Accept-Language 首段。

响应格式

json
{
  "success": true,
  "message": "验证码已发送",
  "expiresIn": 300,
  "retryAfter": 60
}

错误码

状态码错误说明
400invalid_body / invalid_email请求体或邮箱格式无效
401unauthorized缺少有效登录身份
429rate_limited请求过于频繁
502send_failed邮件下发失败
500internal_error服务暂时不可用

POST /my/email/bind

使用 /my/email/send-otp 获取的验证码,将邮箱绑定到当前账号。

认证方式

接受 JWT Token,或带 mobile:full scope 的 OAuth Access Token(wno-...)。

请求体

json
{
  "email": "user@example.com",
  "code": "123456"
}

响应格式

json
{
  "success": true,
  "data": {
    "email": "user@example.com"
  }
}

错误码

状态码错误说明
400invalid_body / invalid_email / invalid_code / code_expired请求体、邮箱或验证码无效
401unauthorized缺少有效登录身份
409email_taken该邮箱已被其他账号绑定
429too_many_attempts验证码尝试次数过多
500internal_error服务暂时不可用

DELETE /my/email

解绑当前账号邮箱。如果解绑后账号没有其它可登录方式,返回 409 last_credential,防止用户锁死账号。

认证方式

接受 JWT Token,或带 mobile:full scope 的 OAuth Access Token(wno-...)。

响应格式

json
{
  "success": true
}

我的凭证管理(/my/credentials/*

「我的凭证」管理子路由组,仅接受 JWT 认证。其他认证方式(API Key / Agent Token)通过 combinedAuth 后会被 jwtOnly guard 拦截返回 403;OAuth token 不在 mobile:full 白名单内,会返回 403 insufficient_scope;无效 token 在认证阶段直接 401 拒绝。

设计意图:用户对自己持有的机器凭证(Agent Token、OAuth 授权)的管理能力,必须使用人类身份(JWT)操作,避免机器凭证自我撤销。

API Key 列表与撤销复用既有 /teams/:teamId/api-keys 链路,未在此暴露独立 REST 端点。

GET /my/credentials/agent-tokens

列出当前用户持有的 active Agent Token 绑定。

过滤条件: owner_user_id = auth.userId AND token_hash IS NOT NULL AND deleted_at IS NULL,按创建时间倒序。

响应格式

json
{
  "items": [
    {
      "binding_id": "uuid",
      "agent_user_id": "uuid",
      "agent_display_name": "我的 Agent",
      "agent_avatar_url": "https://...",
      "team_id": "uuid",
      "team_name": "团队名",
      "team_slug": "team-slug",
      "can_send": true,
      "can_receive": true,
      "created_at": "2026-04-25T..."
    }
  ]
}
字段类型说明
binding_idstringagent_bindings 主键,吊销时使用
agent_user_idstringAgent 对应的虚拟用户 ID
agent_display_namestring | nullAgent 在 profiles 表中的展示名
agent_avatar_urlstring | nullAgent 头像 URL
team_id / team_name / team_slugstring | nullAgent 所属团队(可能为空,代表个人 Agent)
can_send / can_receivebooleanAgent 当前的双向通信开关
created_atstringAgent 绑定创建时间(ISO 8601)

DELETE /my/credentials/agent-tokens/:bindingId

吊销指定 Agent Token,写 token_hash = null 保留绑定本体(与 /team-agents/.../revoke-token 行为一致)。

响应格式

成功(首次撤销):

json
{ "success": true }

幂等(已撤销过):

json
{ "success": true, "alreadyRevoked": true }

错误码

状态码错误说明
401Missing or invalid authorization header / Invalid token缺少认证或 token 无效(在 combinedAuth 阶段拦截)
403This endpoint only accepts JWT authentication凭证有效但非 JWT(API Key / Agent Token 通过 combinedAuth 后由 jwtOnly guard 拒绝)
403Forbiddenbinding 不属于当前用户
404Agent binding not foundbinding 不存在或已软删除
500Failed to revoke agent token数据库写入失败

GET /my/credentials/agent-bindings-as-agent

被绑视角(2026-06-10 新增):列出哪些团队把当前用户绑定为 Agentagent_bindings.agent_user_id = auth.userId AND deleted_at IS NULL)。与上面的 agent-tokens(我授权给别人的)互为对称视角。

响应格式

json
{
  "items": [
    {
      "binding_id": "uuid",
      "owner_user_id": "uuid",
      "owner_display_name": "授权人昵称",
      "team_id": "uuid",
      "team_name": "团队名",
      "team_slug": "team-slug",
      "can_send": true,
      "can_receive": true,
      "created_at": "2026-06-10T08:00:00.000Z"
    }
  ]
}

DELETE /my/credentials/agent-bindings-as-agent/:bindingId

被绑方主动解除 Agent 绑定:软删除整条 binding 并同时置空 token_hash(与团队侧删除 Agent 同语义),解除后该团队不能再通过此绑定调用当前用户。权限校验按 agent_user_id = auth.userId

响应 200

json
{ "success": true }

错误码

状态码错误说明
403Forbiddenbinding 的被绑方不是当前用户
404Agent binding not foundbinding 不存在或已软删除
500Failed to remove agent binding数据库写入失败

GET /my/credentials/oauth-authorizations

列出当前用户授权过的第三方 OAuth 应用,按 app_id 聚合(仅展示 active token,且应用未被软删除)。

过滤条件: oauth_tokens.user_id = auth.userId AND oauth_tokens.revoked_at IS NULL AND oauth_apps.deleted_at IS NULL

聚合规则: 同一应用的多枚 token 合并为一条;scopes 取并集;authorized_at 取最新;active_token_count 计数。

响应格式

json
{
  "items": [
    {
      "app_id": "uuid",
      "app_name": "我的应用",
      "app_logo_url": "https://...",
      "scopes": ["documents:read", "runs:write"],
      "authorized_at": "2026-04-25T...",
      "active_token_count": 1
    }
  ]
}

已禁用的应用(disabled_at IS NOT NULL)仍会展示,让用户感知后主动撤销。已删除的应用(deleted_at IS NOT NULL)不展示。

DELETE /my/credentials/oauth-authorizations/:appId

撤销该应用下当前用户的所有 active token。严格按 user_id + app_id 过滤,不会影响其他用户的授权(与 admin 端的 revoke_all_oauth_tokens_for_app RPC 语义不同)。

响应格式

json
{ "success": true, "revokedCount": 2 }

幂等:若该应用下当前用户已无 active token,返回 revokedCount: 0

错误码

状态码错误说明
401Missing or invalid authorization header / Invalid token缺少认证或 token 无效(在 combinedAuth 阶段拦截)
403This endpoint only accepts JWT authentication凭证有效但非 JWT(API Key / Agent Token 通过 combinedAuth 后由 jwtOnly guard 拒绝)
500Failed to revoke oauth authorization数据库写入失败

账号聚合与站点权限

以下两个端点只接受浏览器用户会话 JWT,不接受 API Key、Agent Token 或 OAuth Token。

GET /my/account

聚合返回 Auth 用户、Profile、站点授权和微信绑定状态,供账号设置页一次性加载。

GET /my/site-permissions

返回当前用户在 site 资源上的显式 grants,用于前端权限入口和管理员能力判断。

AI Workflow Editor