Skip to content

鉴权机制 ​

Notanote API 的所有第三方接口均要求同时提供两种鉴权凭证,缺一不可:

  • 应用身份凭证(TID + SecretKey):证明调用来自你的应用
  • 用户授权凭证(name + access_token):证明玩家已同意授权

鉴权凭证概览 ​

凭证内容证明什么是否必须
应用身份凭证TID + SecretKey你是哪个应用是
用户授权凭证name + access_token玩家同意授权是

应用身份凭证(TID + SecretKey) ​

使用方式 ​

在所有第三方接口的请求体中传入 tid 和 secretkey:

json
{
  "tid": 1001,
  "secretkey": "your-secret-key"
}

Notanote 服务端会校验 tid + secretkey 是否匹配你的应用记录。不匹配则返回 TIDVerifyFailed。

SecretKey 保管

SecretKey 等同于你的应用密码,只能在服务端使用,禁止写入客户端代码或前端配置。泄露后攻击者可以冒充你的应用发起任意请求,包括拉取玩家存档、伪造授权流程。

用户授权凭证(WebAuth) ​

WebAuth 是 Notanote 提供给第三方应用的 OAuth 风格网页授权机制。你的应用通过 WebAuth 可以获取玩家授权的 access_token,进而读取该玩家的存档数据。

整体流程 ​

mermaid
sequenceDiagram
    participant App as 你的服务端
    participant Nano as Notanote API
    participant User as 玩家浏览器

    App->>Nano: ① POST /webauth/get-session
    Nano-->>App: 返回 auth-session(5 分钟有效)

    App->>User: ② 302 重定向到 Notanote 授权页

    User->>Nano: ③ 玩家登录并确认授权
    Nano->>Nano: 校验身份 → 生成 access_token → 作废 auth-session
    Nano-->>User: ④ 返回 redirect_url

    User->>App: ⑤ 浏览器跳转到 callback(携带 access_token + state)

    App->>App: ⑥ 校验 state,存储 access_token

步骤说明 ​

步骤一:获取临时会话 ​

你的服务端用 tid + secretkey 向 Notanote 换取 auth-session,同时传入:

  • state:你生成的随机字符串,用于 CSRF 防护
  • callback:授权完成后的回跳地址

具体接口见下方 获取临时会话。

步骤二:引导玩家授权 ​

将玩家浏览器重定向到 Notanote 授权页面,URL 中携带 auth-session:

https://nano.notanote.cn/authorize?auth-session={你的 auth-session}

步骤三:玩家确认授权 ​

授权页通过 auth-session 查询你的应用信息(名称、作者、授权范围),展示给玩家确认。玩家在授权页输入 Notanote 账号密码后:

  • Notanote 校验玩家身份
  • 生成 access_token
  • 作废 auth-session(一次性使用,无法重放)
  • 返回 redirect_url 给前端

步骤四:浏览器跳转 ​

前端执行跳转,浏览器访问你的 callback 地址,授权参数通过 URL query 传递:

参数说明
name玩家的 Notanote 用户名
access_token第三方授权令牌
state你在步骤一传入的 state,原样回传

步骤五:校验 state ​

你的 callback 页面收到请求后,必须校验 state 与步骤一发出的一致,通过后再存储 access_token。

js
// 伪代码
if (receivedState !== yourOriginalState) {
  // state 不匹配,拒绝本次回调,可能是 CSRF 攻击
  return res.status(403).send('state 校验失败');
}
// 校验通过,安全地存储 access_token

关键设计

  • 服务端不主动请求 callback:Notanote 返回 redirect_url 由浏览器跳转完成回调。既避免 SSRF 风险,也避免服务端到第三方服务端之间的网络故障影响授权流程。
  • state 由你全权管理:state 由你生成并传入,Notanote 原样存入、原样回传,不解析 state 内容。生成与校验完全由你负责。

展示模式(callback="show") ​

将 callback 设为字符串 "show" 即启用展示模式,专为 QQ 机器人等无法提供回调地址的接入场景 设计。与 URL 回调模式的差异从授权完成那一刻开始:浏览器不跳转,而是在授权页直接展示一个授权码,由玩家复制后手动交给第三方接入者。

授权码格式 ​

展示模式下页面展示给玩家的是一个完整的授权码字符串,格式为:

{name}.{token}
组成部分含义
name玩家的 Notanote 用户名
.固定分隔符
token第三方授权令牌(access_token)

例如玩家 player1 授权成功后,页面展示的授权码形如 player1.a1b2c3d4e5f6。

第三方接入者收到授权码后,以第一个 . 为界拆分:前半部分作为 Name,后半部分作为 Token,即可调用后续第三方接口(如存档读取):

js
// 解析展示模式授权码
const dot = code.indexOf(".");
const name = code.slice(0, dot);   // 玩家用户名
const token = code.slice(dot + 1); // access_token

流程 ​

mermaid
sequenceDiagram
    participant App as 你的服务端
    participant Nano as Notanote API
    participant User as 玩家浏览器
    participant 3rd as 第三方接入者

    App->>Nano: ① POST /webauth/get-session(callback="show")
    Nano-->>App: 返回 auth-session

    App->>User: ② 302 重定向到 Notanote 授权页
    User->>Nano: ③ 玩家登录并确认授权
    Nano->>Nano: 生成 access_token,作废 auth-session
    Nano-->>User: ④ 页面直接展示授权码(name.token)

    User->>3rd: ⑤ 玩家复制授权码,手动发送给第三方接入者
    3rd->>3rd: ⑥ 按第一个 "." 拆分,得到 name 与 access_token
    3rd->>Nano: ⑦ 用 name + access_token 调用第三方接口

与 URL 回调模式的区别 ​

对比维度URL 回调模式展示模式(callback="show")
回调方式浏览器自动跳转到你的回调 URL页面直接展示授权码,不跳转
是否需托管需要公网可访问的回调地址不需要任何回调地址
适用场景Web 应用、有服务端的场景QQ 机器人、无法托管回调地址的场景
state 校验在回调路由中校验由你的服务端在处理后续调用时酌情校验
凭证传递name 与 access_token 走 URL query授权码 {name}.{token} 由玩家手动复制

展示模式设计意图

展示模式专为解决 QQ 机器人等无法提供回调地址的接入场景 而设计。玩家在 Notanote 授权页完成授权后,页面直接展示授权码({name}.{token}),玩家复制后发送给第三方接入者(如 QQ 群内机器人客服),第三方拆分出 name 与 token 即可调用后续接口。

获取临时会话 POST /webauth/get-session ​

获取临时授权会话。由你的服务端调用,禁止在前端直接调用。

接口地址:POST https://api.notanote.cn/webauth/get-session

请求参数 ​

字段类型必填说明
tidnumber是你的第三方应用 ID
secretkeystring是你的第三方应用密钥
scopestring是授权范围,目前仅支持 access_token
callbackstring是授权完成后的回跳地址(合法 URL),或填入 "show" 启用展示模式
statestring是你生成的随机字符串,用于 CSRF 防护,建议至少 16 字符

请求示例 ​

json
{ // 下面是 form-data 转化成 json 的形式
  "tid": 1001,
  "secretkey": "{your-secret-key}",
  "scope": "access_token",
  "callback": "{https://your-app.com/oauth/callback}",
  "state": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6...(随机的 16~32 bytes 字符串)"
}

成功响应 ​

json
{
  "Status": true,
  "Response": {
    "Identifier": "nano.api.v2.webauth.get-session.succeed",
    "Data": {
      "auth-session": "AbC123...XYz789",
      "expire_in": 300
    }
  }
}
字段类型说明
auth-sessionstring临时会话令牌,用于构造授权页 URL
expire_innumber有效期(秒),固定为 300(5 分钟)

callback 由你传入

callback 由你在请求时传入,合法值包括:

  • HTTPS URL:授权完成后浏览器自动跳转到该地址
  • "show":授权完成后在页面直接展示授权码({name}.{token}),适用于 QQ 机器人等无法托管回调地址的场景

你必须确保 secretkey 不泄露,否则攻击者可伪造 callback 劫持授权结果。

失败响应 ​

Identifier说明处理建议
nano.api.v2.webauth.get-session.failed.TIDVerifyFailedtid 或 secretkey 错误检查凭证是否正确、应用是否被禁用
nano.api.v2.webauth.get-session.failed.serverError服务端临时故障稍后重试,持续失败请联系运营方

Scope 说明 ​

目前仅支持一种 scope:access_token,表示申请获取玩家的第三方授权令牌。授权完成后,Notanote 会生成一个专用于第三方接口的 access_token,并通过回调地址回传给你。

回调地址收到的 query 参数:

参数说明
name玩家的 Notanote 用户名
access_token第三方授权令牌
state你在第一步传入的 state,原样回传

access_token 权限隔离 ​

access_token 仅限第三方接口使用,无法访问 Notanote 核心接口(如账号、用户、应用管理等)。即使令牌泄露,影响范围也只限于第三方接口,玩家核心数据不受影响。

接口类别access_token 能否访问
第三方接口是
核心接口否
WebAuth 接口否(无法用于续期)

安全注意事项 ​

接入 WebAuth 时请务必遵循以下安全规范,否则可能导致应用被冒充、玩家数据泄露等严重后果。

1. SecretKey 仅限服务端 ​

SecretKey 禁止写入:

  • 前端代码(包括编译后的产物)
  • 客户端配置文件
  • 版本控制系统(Git)
  • 客户端可读的 LocalStorage / Cookie

泄露后攻击者可以冒充你的应用发起任意请求。建议通过环境变量或密钥管理服务(KMS)注入。

2. 必须校验 state ​

你的 callback 收到请求后,务必校验 state 与步骤一中发出的一致。如果不一致,说明这不是你发起的授权,应当拒绝。这是防御 CSRF 攻击的关键手段。

js
if (receivedState !== yourOriginalState) {
  // 拒绝这次回调,可能遭到 CSRF 攻击
  return;
}

最佳实践:

  • state 必须由服务端生成(不要在前端生成)
  • state 使用加密安全的随机数,长度至少 16 字符
  • state 一次性使用,校验通过后立即删除
  • 在 auth-session 有效期内(5 分钟)必须完成校验

3. auth-session 一次性使用 ​

auth-session 在玩家确认授权后立即作废,无法重放。即使攻击者截获了 auth-session,也无法用它重复发起授权。

4. auth-session 短 TTL ​

auth-session 有效期仅 5 分钟,降低泄露风险。你的服务端换取 auth-session 后应尽快引导玩家完成授权,避免会话过期导致授权失败。

5. 玩家身份二次验证 ​

授权页会要求玩家输入 Notanote 账号密码,确保是玩家本人操作,而非攻击者伪造。

6. 无 SSRF 风险 ​

Notanote 服务端不主动请求 callback,回调由玩家浏览器跳转完成。攻击者无法通过伪造 callback 让 Notanote 服务端扫描你的内网。

7. access_token 暴露处理 ​

浏览器跳转时 access_token 会出现在地址栏和历史记录中。你的 callback 页面应:

  • 在接收后立即用 access_token 完成后续操作
  • 引导玩家离开 callback 页面,避免 token 持续暴露