OAuth 授权
---
闲言APP — OAuth 社交登录接口文档
基础URL:
https://tools.wktyl.com版本: v1.0.0 | 更新时间: 2026-08-15 作者: Xianyan(闲言)团队 支持平台: Apple / Google / GitHub 关联文档: API_USER_SECURITY_DOC
一、概述
OAuth 社交登录让用户用 Apple / Google / GitHub 账号一键登录闲言,无需手动注册。
核心价值: - 降低注册门槛(无密码、无验证码) - 邮箱相同时自动关联已有闲言账号 - 与自有用户名+密码注册完全兼容(双通道并存)
登录流程(4 步):
1. 客户端请求 /api/oauth/config 获取授权 URL
2. 用户在第三方平台完成授权
3. 客户端提交授权凭证到 /api/oauth/login
4. 服务端校验凭证 → 创建/关联账号 → 返回登录 Token
完整时序图(以 GitHub 为例):
mermaid
sequenceDiagram
participant App as 闲言App
participant Svr as 闲言服务端
participant Git as GitHub
App->>Svr: GET /api/oauth/config?platform=github
Svr-->>App: authorize_url + client_id
App->>Git: 跳转授权页
Git-->>App: 回调 + code
App->>Svr: POST /api/oauth/login (platform=github, code)
Svr->>Git: 用 code 换 access_token
Git-->>Svr: access_token + 用户信息
Svr->>Svr: 创建/关联闲言账号
Svr-->>App: token + userinfo + is_new_user
二、快速开始(最小可跑通)
以 GitHub 登录为例,最少只需两步:
# 1. 获取授权 URL
curl "https://tools.wktyl.com/api/oauth/config?platform=github"
# 2. 用户授权后,用 code 换登录态
curl -X POST "https://tools.wktyl.com/api/oauth/login" \
-d "platform=github&code=用户授权返回的code"
返回的
data.token即闲言登录凭证,后续请求带Authorization: Bearer {token}。
三、三平台登录差异对比
三个平台的授权机制不同,客户端 SDK 拿到的凭证也不同:
| 维度 | Apple | GitHub | |
|---|---|---|---|
| 客户端 SDK | sign_in_with_apple |
google_sign_in |
浏览器跳转授权页 |
| 获取凭证 | id_token + authorization_code |
serverAuthCode |
回调 URL 里的 code |
| 提交参数 | platform=apple + id_token + code |
platform=google + code |
platform=github + code |
| 服务端校验 | 验证 JWT 的 issuer 和签名 | 用 code 换 access_token | 用 code 换 access_token |
关键区别:Apple 依赖
id_token(客户端直接拿到 JWT),Google/GitHub 依赖code(服务端二次换取)。
四、接口概览
| 接口 | 方法 | 路径 | 需登录 | 说明 |
|---|---|---|---|---|
| 获取 OAuth 配置 | GET | /api/oauth/config |
❌ | 获取授权 URL 和 client_id |
| 社交登录 | POST | /api/oauth/login |
❌ | 授权凭证换登录 Token |
| 绑定社交账号 | POST | /api/oauth/bind |
✅ | 已登录用户绑定第三方 |
| 解绑社交账号 | POST | /api/oauth/unbind |
✅ | 解除第三方绑定 |
| 已绑定列表 | GET | /api/oauth/bound |
✅ | 查询已绑定平台 |
| 安装数据表 | GET | /api/oauth/install |
❌ | 初始化(运维用) |
五、接口详情
5.1 获取 OAuth 配置
GET /api/oauth/config?platform=apple
获取指定平台的授权 URL 和 client_id,客户端据此拉起第三方授权页。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| platform | string | ✅ | 平台:apple / google / github |
响应示例:
{
"code": 1,
"msg": "",
"data": {
"platform": "github",
"configured": true,
"client_id": "Ov23li...",
"redirect_uri": "https://tools.wktyl.com/oauth/callback",
"authorize_url": "https://github.com/login/oauth/authorize?client_id=...&scope=user:email&state=..."
}
}
若
configured为false,说明该平台未在服务端配置,客户端应隐藏对应登录按钮。
5.2 社交登录
POST /api/oauth/login
核心接口:用第三方授权凭证换取闲言登录 Token。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| platform | string | ✅ | 平台:apple / google / github |
| code | string | 条件 | 授权码(google/github 必填) |
| id_token | string | 条件 | Apple ID Token(apple 必填) |
| device_name | string | ❌ | 设备名称 |
| device_model | string | ❌ | 设备型号 |
| platform_type | string | ❌ | 登录平台(ios/android/web) |
| device_id | string | ❌ | 设备唯一标识 |
| ip_city | string | ❌ | IP 归属地 |
| ip_range | string | ❌ | IP 段范围 |
成功响应:
{
"code": 1,
"msg": "登录成功",
"data": {
"userinfo": {
"id": 42,
"username": "github_abc12345",
"nickname": "octocat",
"email": "user@example.com",
"avatar": "https://avatars.githubusercontent.com/u/..."
},
"token": "xxxxxxxxxxxx",
"is_new_user": true,
"bind_platform": "github"
}
}
关键字段说明:
- is_new_user:true 表示首次登录(可引导用户完善资料),false 表示已有账号
- bind_platform:本次登录使用的第三方平台
- 后续请求用 token 作为 Authorization: Bearer 凭证
5.3 绑定社交账号
POST /api/oauth/bind
已登录的闲言用户,绑定一个第三方账号(一个闲言账号可绑定多个平台)。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| platform | string | ✅ | 平台:apple / google / github |
| code | string | 条件 | 授权码 |
| id_token | string | 条件 | Apple ID Token |
成功响应:
{
"code": 1,
"msg": "绑定成功",
"data": {
"platform": "github",
"openid": "github_12345",
"nickname": "octocat"
}
}
5.4 解绑社交账号
POST /api/oauth/unbind
解除已绑定的第三方账号。
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| platform | string | ✅ | 平台:apple / google / github |
成功响应:
{
"code": 1,
"msg": "解绑成功",
"data": { "platform": "github" }
}
⚠️ 解绑后该第三方账号可重新绑定到其他闲言账号。若用户只有一个登录方式(无密码),解绑前应提示设置密码。
5.5 已绑定列表
GET /api/oauth/bound
查询当前用户已绑定的所有第三方平台。
响应示例:
{
"code": 1,
"msg": "",
"data": {
"bindings": [
{
"platform": "github",
"openid": "github_12345",
"nickname": "octocat",
"avatar": "https://...",
"createtime": 1717200000
}
]
}
}
5.6 安装数据表
GET /api/oauth/install
运维接口,创建 tool_user_oauth 数据表(首次部署时调用一次即可)。
六、数据表设计
tool_user_oauth
| 字段 | 类型 | 说明 |
|---|---|---|
| id | int(11) unsigned | 主键自增 |
| user_id | int(11) unsigned | 闲言用户 ID |
| platform | varchar(30) | 平台(apple/google/github) |
| openid | varchar(128) | 平台用户唯一 ID |
| unionid | varchar(128) | 跨应用联合 ID |
| nickname | varchar(100) | 第三方昵称 |
| avatar | varchar(500) | 第三方头像 URL |
| access_token | text | 访问令牌 |
| refresh_token | text | 刷新令牌 |
| expires_at | int(11) unsigned | 令牌过期时间戳 |
| createtime | int(11) unsigned | 创建时间戳 |
| updatetime | int(11) unsigned | 更新时间戳 |
索引: uk_platform_openid(platform, openid)(唯一,防止重复绑定)、idx_user_id(user_id)
七、错误码
统一约定:
code = 1成功,code = 0业务失败(具体原因看msg)。
| code | msg | 触发场景 |
|---|---|---|
| 0 | 不支持的平台 | platform 参数不是 apple/google/github |
| 0 | 平台未配置 | 服务端未配置该平台的 client_id/secret |
| 0 | OAuth验证失败 | 授权码 / id_token 无效或已过期 |
| 0 | 该账号已被其他用户绑定 | openid 已绑定到别的闲言账号 |
| 0 | 已绑定该平台 | 重复绑定同一平台 |
| 0 | 请求过于频繁 | 超过频率限制 |
八、频率限制
| 接口 | 上限 | 时间窗口 |
|---|---|---|
| login | 30 次 | 5 分钟 |
| bind | 20 次 | 1 小时 |
| unbind | 20 次 | 1 小时 |
九、安全说明
服务端校验(核心安全机制):
| 平台 | 校验方式 | 为何安全 |
|---|---|---|
| Apple | 验证 JWT 的 issuer 和签名 |
不信任客户端解析,服务端独立验签 |
| 用 code 换 access_token,再取用户信息 | code 只能被服务端换一次 | |
| GitHub | 用 code 换 access_token | 同上,客户端无法伪造 |
其他安全约束:
- 同一 openid 只能绑定一个闲言账号(数据库唯一索引兜底)
- 邮箱相同的 OAuth 用户自动关联已有账号(避免一人多号)
- state 参数防 CSRF(config 返回的 authorize_url 中携带,服务端回校)
- OAuth 凭证(access_token/refresh_token)仅存服务端,不下发客户端