摸鱼派第三方登录(OAuth / OpenID)接入说明【新】
摸鱼派第三方登录(OAuth / OpenID)接入说明
版本:2026-07-06
1. 能力概览
摸鱼派提供一套兼容 OpenID 2.0 登录流程的第三方授权能力。第三方站点可以引导用户跳转到摸鱼派完成登录与授权,随后在服务端校验回跳参数,并使用授权得到的访问令牌读取用户资源。
当前支持:
- 使用摸鱼派账号登录第三方站点
- 按授权范围读取用户基础信息、用户详细资料、积分记录、公开发帖记录、VIP 信息
- 使用
Authorization: Bearer <access_token>调用 OAuth 用户资源接口 - 使用
refresh_token无感续签access_token
生产环境域名为
https://fishpi.cn。本文示例中的https://example.com请替换为第三方站点自己的服务端地址。
2. 接入流程
- 第三方站点生成
/openid/login授权地址,并让用户浏览器跳转到摸鱼派。 - 用户在摸鱼派确认授权范围。
- 摸鱼派回跳到第三方站点的
openid.return_to。 - 第三方站点服务端调用
/openid/verify校验回跳参数。 - 校验通过后获得
access_token、refresh_token与最终授权范围。 - 第三方站点使用
access_token调用用户资源接口。 access_token过期后,使用/openid/token续签。
3. 授权范围
第三方站点在 /openid/login 中通过 fishpi.scope 声明需要的权限。多个权限可使用空格或英文逗号分隔。
| Scope | 说明 |
|---|---|
profile.read |
读取用户基础信息 |
profile.detail.read |
读取用户详细资料 |
points.read |
读取用户积分余额与积分流水 |
articles.read |
读取用户公开发帖记录 |
membership.read |
读取用户 VIP 信息 |
说明:
- 不传
fishpi.scope时,默认按profile.read处理。 - 第三方站点请求的权限会在授权页默认勾选,且不可取消。
- 用户可以额外勾选站点未请求的权限。
- 最终授权范围缺少站点请求的权限时,本次授权失败。
- 用户资源接口只接受
Authorization: Bearer <access_token>,不接受apiKey。
4. 发起登录
GET /openid/login
第三方站点构造授权地址,并让用户浏览器跳转到该地址。
请求:
| Key | 必填 | 说明 | 示例 |
|---|---|---|---|
openid.ns |
是 | 固定为 OpenID 2.0 协议地址 | http://specs.openid.net/auth/2.0 |
openid.mode |
是 | 固定为checkid_setup |
checkid_setup |
openid.return_to |
是 | 授权完成后的回调地址 | https://example.com/callback |
openid.realm |
是 | 信任域,必须是openid.return_to 的前缀 |
https://example.com |
openid.identity |
是 | 固定为 OpenID identifier_select | http://specs.openid.net/auth/2.0/identifier_select |
openid.claimed_id |
是 | 同openid.identity |
http://specs.openid.net/auth/2.0/identifier_select |
fishpi.scope |
否 | 授权范围,空格或逗号分隔 | profile.read profile.detail.read membership.read |
请求示例:
https://fishpi.cn/openid/login?openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.mode=checkid_setup&openid.return_to=https%3A%2F%2Fexample.com%2Fcallback&openid.realm=https%3A%2F%2Fexample.com&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&fishpi.scope=profile.read+profile.detail.read+membership.read
URL 参数需要按规范编码。生产环境回调地址建议使用 HTTPS,本地开发可使用
localhost或127.0.0.1。
5. 接收授权回跳
用户确认授权后,摸鱼派会重定向到 openid.return_to,并在 URL 中携带 OpenID 参数。
常见回跳参数:
| Key | 说明 |
|---|---|
openid.ns |
协议声明 |
openid.mode |
固定为id_res |
openid.op_endpoint |
摸鱼派 OpenID 服务入口 |
openid.claimed_id |
用户唯一标识 URL |
openid.identity |
用户唯一标识 URL |
openid.return_to |
回调地址 |
openid.response_nonce |
一次性随机串 |
openid.assoc_handle |
关联信息 |
openid.signed |
参与签名的字段列表 |
openid.sig |
签名值 |
openid.claimed_id / openid.identity 末尾通常包含用户 oId,例如:
https://fishpi.cn/openid/id/1659430635383
回跳参数不能直接作为可信登录结果,必须先调用
/openid/verify校验。
6. 校验回跳参数
POST /openid/verify
第三方站点服务端必须调用该接口校验回跳参数真实性。
请求:
| Key | 说明 |
|---|---|
Content-Type |
application/json |
| 请求体 | 回跳收到的openid.* 参数 |
openid.mode |
调用校验时改为check_authentication |
请求示例:
curl --location --request POST 'https://fishpi.cn/openid/verify' \
--header 'Content-Type: application/json' \
--data-raw '{
"openid.ns": "http://specs.openid.net/auth/2.0",
"openid.mode": "check_authentication",
"openid.op_endpoint": "https://fishpi.cn/openid",
"openid.claimed_id": "https://fishpi.cn/openid/id/1659430635383",
"openid.identity": "https://fishpi.cn/openid/id/1659430635383",
"openid.return_to": "https://example.com/callback",
"openid.response_nonce": "2026-07-06T00:00:00Zxxxxxxxxxx",
"openid.assoc_handle": "1234567890",
"openid.signed": "op_endpoint,claimed_id,identity,return_to,response_nonce,assoc_handle",
"openid.sig": "xxx"
}'
成功响应为纯文本:
ns:http://specs.openid.net/auth/2.0
is_valid:true
scope:profile.read profile.detail.read membership.read
token_type:Bearer
access_token:xxx
expires_in:604800
refresh_token:xxx
refresh_expires_in:31104000
失败响应为纯文本:
ns:http://specs.openid.net/auth/2.0
is_valid:false
响应字段:
| Key | 说明 | 示例 |
|---|---|---|
is_valid |
校验结果 | true |
scope |
用户最终授权范围 | profile.read profile.detail.read membership.read |
token_type |
令牌类型 | Bearer |
access_token |
OAuth 用户资源访问令牌 | xxx |
expires_in |
access_token 有效期,单位秒 |
604800 |
refresh_token |
OAuth 续签令牌 | xxx |
refresh_expires_in |
refresh_token 空闲有效期,单位秒 |
31104000 |
/openid/verify只用于校验登录回跳参数。续签令牌请使用/openid/token。
7. 续签访问令牌
POST /openid/token
使用 refresh_token 续签 OAuth 访问令牌。不需要登录态,不接受 apiKey。
请求:
| Key | 说明 | 示例 |
|---|---|---|
grant_type |
固定为refresh_token |
refresh_token |
refresh_token |
OAuth 续签令牌 | xxx |
请求示例:
curl --location --request POST 'https://fishpi.cn/openid/token' \
--header 'Content-Type: application/json' \
--data-raw '{
"grant_type": "refresh_token",
"refresh_token": "xxx"
}'
成功响应:
{
"code": 0,
"msg": "",
"data": {
"token_type": "Bearer",
"access_token": "xxx",
"expires_in": 604800,
"refresh_token": "xxx",
"refresh_expires_in": 31104000,
"scope": "profile.read profile.detail.read membership.read"
}
}
响应字段:
| Key | 说明 | 示例 |
|---|---|---|
code |
0 为成功,-1 为失败 |
0 |
msg |
错误消息 | |
data.token_type |
令牌类型 | Bearer |
data.access_token |
新访问令牌 | xxx |
data.expires_in |
访问令牌有效期,单位秒 | 604800 |
data.refresh_token |
新续签令牌 | xxx |
data.refresh_expires_in |
续签令牌空闲有效期,单位秒 | 31104000 |
data.scope |
原授权范围 | profile.read profile.detail.read membership.read |
续签规则:
access_token默认有效期为 7 天。refresh_token默认空闲有效期为 360 天。refresh_token最长不超过首次授权后 720 天。- 每次续签都会返回新的
refresh_token,旧refresh_token立即失效。 - 已轮换的旧
refresh_token再次使用时,同一令牌族下仍有效的令牌会被撤销。
请把
refresh_token保存在服务端或可信客户端,不要暴露到前端页面、URL、日志、埋点或报错信息中。
8. 查询用户基础信息
GET /openid/user/profile
查询当前 OAuth 授权用户的基础信息。需要 profile.read 权限。
请求:
| Key | 说明 | 示例 |
|---|---|---|
Authorization |
Bearer 访问令牌 | Bearer xxx |
请求示例:
curl --location --request GET 'https://fishpi.cn/openid/user/profile' \
--header 'Authorization: Bearer xxx'
成功响应:
{
"code": 0,
"msg": "",
"data": {
"userId": "1659430635383",
"userName": "admin",
"userNickname": "管理员",
"userAvatarURL": "https://file.fishpi.cn/a.png"
}
}
响应字段:
| Key | 说明 | 示例 |
|---|---|---|
code |
0 为成功,-1 为失败 |
0 |
msg |
错误消息 | |
data.userId |
用户oId |
1659430635383 |
data.userName |
用户名 | admin |
data.userNickname |
昵称 | 管理员 |
data.userAvatarURL |
头像 | https://file.fishpi.cn/a.png |
9. 查询用户详细资料
GET /openid/user/detail
查询当前 OAuth 授权用户的详细资料。需要 profile.detail.read 权限。
请求:
| Key | 说明 | 示例 |
|---|---|---|
Authorization |
Bearer 访问令牌 | Bearer xxx |
请求示例:
curl --location --request GET 'https://fishpi.cn/openid/user/detail' \
--header 'Authorization: Bearer xxx'
成功响应:
{
"code": 0,
"msg": "",
"data": {
"userName": "admin",
"userOnlineFlag": true,
"onlineMinute": 1000,
"userURL": "https://example.com",
"userNickname": "管理员",
"userCity": "北京",
"userAvatarURL": "https://file.fishpi.cn/a.png",
"userPoint": 183939,
"userIntro": "摸鱼中",
"oId": "1659430635383",
"userNo": "1",
"userAppRole": "0",
"sysMetal": {
"list": []
},
"followerCount": 10,
"followingUserCount": 5,
"userRole": "普通用户",
"cardBg": ""
}
}
响应字段:
| Key | 说明 | 示例 |
|---|---|---|
code |
0 为成功,-1 为失败 |
0 |
msg |
错误消息 | |
data.userName |
用户名 | admin |
data.userOnlineFlag |
是否在线 | true |
data.onlineMinute |
在线分钟数 | 1000 |
data.userURL |
个人链接 | https://example.com |
data.userNickname |
昵称 | 管理员 |
data.userCity |
公开城市 | 北京 |
data.userAvatarURL |
头像 | https://file.fishpi.cn/a.png |
data.userPoint |
当前积分 | 183939 |
data.userIntro |
简介 | 摸鱼中 |
data.oId |
用户oId |
1659430635383 |
data.userNo |
用户编号 | 1 |
data.userAppRole |
站内身份 | 0 |
data.sysMetal |
展示勋章 | {"list":[]} |
data.followerCount |
粉丝数 | 10 |
data.followingUserCount |
关注数 | 5 |
data.userRole |
角色名 | 普通用户 |
data.cardBg |
卡片背景 |
本接口只返回当前 Bearer token 所属用户,不支持传
userId代查。不会返回邮箱、手机号、QQ、登录 IP、密码、2FA 密钥、token/key 或完整用户对象。userCity仅在用户公开地理位置时返回。
10. 查询用户 VIP 信息
GET /openid/user/membership
查询当前 OAuth 授权用户的 VIP 状态。需要 membership.read 权限。
请求:
| Key | 说明 | 示例 |
|---|---|---|
Authorization |
Bearer 访问令牌 | Bearer xxx |
请求示例:
curl --location --request GET 'https://fishpi.cn/openid/user/membership' \
--header 'Authorization: Bearer xxx'
成功响应:
{
"code": 0,
"msg": "",
"data": {
"active": true,
"state": 1,
"lvCode": "VIP1",
"expiresAt": 1760000000000,
"configJson": "{}"
}
}
响应字段:
| Key | 说明 | 示例 |
|---|---|---|
code |
0 为成功,-1 为失败 |
0 |
msg |
错误消息 | |
data.active |
VIP 是否有效 | true |
data.state |
会员状态 | 1 |
data.lvCode |
VIP 等级编码 | VIP1 |
data.expiresAt |
到期时间,毫秒;0 为永久 |
1760000000000 |
data.configJson |
用户 VIP 配置 | {} |
非 VIP 或已过期响应:
{
"code": 0,
"msg": "",
"data": {
"active": false,
"state": 0,
"lvCode": "",
"expiresAt": 0,
"configJson": ""
}
}
本接口只返回当前 Bearer token 所属用户,不支持传
userId代查。不会返回价格、支付、退款或后台维护记录。
11. 查询用户积分记录
GET /openid/user/points
分页查询当前 OAuth 授权用户的积分余额和积分记录。需要 points.read 权限。
请求:
| Key | 说明 | 示例 |
|---|---|---|
Authorization |
Bearer 访问令牌 | Bearer xxx |
p |
页码,默认1 |
1 |
size |
每页数量,默认20,最大 200 |
20 |
请求示例:
curl --location --request GET 'https://fishpi.cn/openid/user/points?p=1&size=20' \
--header 'Authorization: Bearer xxx'
成功响应:
{
"code": 0,
"msg": "",
"data": {
"userId": "1659430635383",
"userPoint": 183939,
"records": [
{
"oId": "1760000000000",
"fromId": "sys",
"toId": "1659430635383",
"sum": 20,
"type": 8,
"time": 1760000000000,
"dataId": "1760000000000",
"memo": "hello",
"operation": "+",
"balance": 183939,
"displayType": "活动收益",
"description": "签到奖励"
}
],
"pagination": {
"paginationCurrentPageNum": 1,
"paginationPageSize": 20,
"paginationRecordCount": 100,
"paginationPageCount": 5,
"paginationPageNums": [1, 2, 3, 4, 5]
}
}
}
响应字段:
| Key | 说明 | 示例 |
|---|---|---|
code |
0 为成功,-1 为失败 |
0 |
msg |
错误消息 | |
data.userId |
用户oId |
1659430635383 |
data.userPoint |
当前积分 | 183939 |
data.records |
积分记录列表 | |
data.records[].oId |
记录oId |
1760000000000 |
data.records[].fromId |
支出用户oId |
sys |
data.records[].toId |
收入用户oId |
1659430635383 |
data.records[].sum |
积分数量 | 20 |
data.records[].type |
记录类型 | 8 |
data.records[].time |
记录时间 | 1760000000000 |
data.records[].dataId |
关联数据 | 1760000000000 |
data.records[].memo |
备注 | hello |
data.records[].operation |
收支方向 | + |
data.records[].balance |
操作后余额 | 183939 |
data.records[].displayType |
类型名称 | 活动收益 |
data.records[].description |
记录描述 | 签到奖励 |
data.pagination.paginationCurrentPageNum |
当前页 | 1 |
data.pagination.paginationPageSize |
每页数量 | 20 |
data.pagination.paginationRecordCount |
总记录数 | 100 |
data.pagination.paginationPageCount |
总页数 | 5 |
data.pagination.paginationPageNums |
页码列表 | [1,2,3,4,5] |
description为已格式化展示文本,客户端可直接展示。
12. 查询用户发帖记录
GET /openid/user/articles
分页查询当前 OAuth 授权用户的公开发帖记录。需要 articles.read 权限。
请求:
| Key | 说明 | 示例 |
|---|---|---|
Authorization |
Bearer 访问令牌 | Bearer xxx |
p |
页码,默认1 |
1 |
size |
每页数量,默认20,最大 100 |
20 |
请求示例:
curl --location --request GET 'https://fishpi.cn/openid/user/articles?p=1&size=20' \
--header 'Authorization: Bearer xxx'
成功响应:
{
"code": 0,
"msg": "",
"data": {
"userId": "1659430635383",
"articles": [
{
"oId": "1760000000000",
"articleTitle": "摸鱼",
"articlePermalink": "/article/1760000000000",
"articleTags": "摸鱼,生活",
"articleCreateTime": 1760000000000,
"articleUpdateTime": 1760000000000,
"articleCommentCount": 3,
"articleViewCount": 100,
"articleType": 0,
"articlePerfect": 0
}
],
"pagination": {
"paginationCurrentPageNum": 1,
"paginationPageSize": 20,
"paginationRecordCount": 100,
"paginationPageCount": 5,
"paginationPageNums": [1, 2, 3, 4, 5]
}
}
}
响应字段:
| Key | 说明 | 示例 |
|---|---|---|
code |
0 为成功,-1 为失败 |
0 |
msg |
错误消息 | |
data.userId |
用户oId |
1659430635383 |
data.articles |
发帖记录列表 | |
data.articles[].oId |
帖子oId |
1760000000000 |
data.articles[].articleTitle |
标题 | 摸鱼 |
data.articles[].articlePermalink |
链接 | /article/1760000000000 |
data.articles[].articleTags |
标签 | 摸鱼,生活 |
data.articles[].articleCreateTime |
创建时间 | 1760000000000 |
data.articles[].articleUpdateTime |
更新时间 | 1760000000000 |
data.articles[].articleCommentCount |
回帖数 | 3 |
data.articles[].articleViewCount |
浏览数 | 100 |
data.articles[].articleType |
帖子类型 | 0 |
data.articles[].articlePerfect |
是否优选 | 0 |
data.pagination.paginationCurrentPageNum |
当前页 | 1 |
data.pagination.paginationPageSize |
每页数量 | 20 |
data.pagination.paginationRecordCount |
总记录数 | 100 |
data.pagination.paginationPageCount |
总页数 | 5 |
data.pagination.paginationPageNums |
页码列表 | [1,2,3,4,5] |
发帖记录只返回公开、非匿名、未删除发帖,不包含正文、草稿、IP、UA。
13. 权限与错误处理
资源接口统一使用 Bearer 访问令牌:
Authorization: Bearer <access_token>
常见失败场景:
| 场景 | 结果 |
|---|---|
缺少Authorization |
无权限 |
access_token 伪造或过期 |
无权限 |
access_token 缺少接口所需 scope |
无权限 |
使用refresh_token 调资源接口 |
无权限 |
/openid/token 使用错误 grant_type |
参数错误 |
重复使用已轮换的refresh_token |
无权限,同一令牌族撤销 |
接口失败响应通常为 JSON:
{
"code": -1,
"msg": "无权限"
}
/openid/verify 保持 OpenID 兼容响应,失败时返回纯文本 is_valid:false。
14. 安全建议
access_token只用于调用 OAuth 用户资源接口。refresh_token只用于/openid/token续签。- 服务端应保存最终授权
scope,调用资源接口前先判断权限。 - 不要把令牌写入前端源码、URL、日志、错误堆栈或第三方统计。
- 回调参数必须由服务端调用
/openid/verify校验后再建立登录态。 - 第三方站点只应请求业务必需的 scope。
收到
太强辣!
感谢使用手册
tql辣
太强辣!
技术贴!
😋学习学习