认证与 CSRF
Cookie / Bearer / X-API-Token、令牌换取、CSRF 与同源
路径未版本化
最后更新:2026-10-25
认证
API 支持三种身份传递方式,按以下顺序解析:
- 网页会话 Cookie:浏览器登入网页后自动携带,名称默认
class32601.sid,HttpOnly、SameSite=Lax,有效期 7 天;COOKIE_SECURE=1时只通过 HTTPS 发送。 Authorization: Bearer <token>:推荐给 App、小程序、脚本和第三方端。X-API-Token: <token>:与 Bearer 等价的备用头,适合不方便设置Authorization的客户端。
Cookie 会话存在时优先使用 Cookie;没有 Cookie 时才解析令牌。两个头都接受
Bearer <token> 和裸 token,但推荐统一写成 Authorization: Bearer <token>。
没有有效 Cookie 会话时,只要请求带了无效或过期的令牌,即使访问公开接口也会直接返回 401 UNAUTHORIZED(身份中间件先于路由执行)。
获取访问令牌
先用网页会话 Cookie 调用 POST /api/auth/token 换取跨端令牌。令牌是无状态的 HMAC 签名串,默认有效期 30 天;服务端不单独存库,因此没有刷新或吊销接口,修改 SESSION_SECRET 会让所有旧令牌失效。
curl -s -X POST "$BASE/api/auth/token" \
-H "Cookie: class32601.sid=$SESSION_COOKIE" \
-H "Content-Type: application/json" \
-d '{"ttlSec": 86400}'
请求体可选;ttlSec 传正整数时按该秒数签发,不传、传 0 或非正数时使用默认 30 天。服务端未对 ttlSec 设置上限,调用方应自行限制合理范围。
需要认证的接口
| 类别 | 接口 |
|---|---|
| 公开(不需要身份) | GET /api/health、GET /api/platforms、POST /api/identities/bind、POST /api/auth/desk、GET /api/auth/desk/:scene、GET /api/auth/desk/:scene/qrcode、POST /api/auth/mini、GET /api/auth/mini/status、GET /api/app/version |
| 需要认证 | POST /api/auth/token、GET/POST /api/me、POST /api/me/password、POST /api/me/password/clear、待办、课表、日历、分组、通知、身份查询与绑定码相关接口 |
CSRF 与同源校验
网页表单和 API 的规则不同,不要混用:
| 场景 | 规则 | 失败结果 |
|---|---|---|
| 网页非 GET 表单 | 必须带隐藏字段 _csrf(也兼容 body 的 csrf 字段),或请求头 X-CSRF-Token,值来自会话令牌;CSRF_ENABLED=0 时关闭,生产不应关闭 |
403 网页错误页 |
/api/** |
不受网页 CSRF 中间件校验(路由层显式豁免) | — |
| API + Cookie 会话 + 写操作(POST 等) | 有 Cookie 会话的写操作:优先检查 Origin,没有时才看 Referer;来源必须是同源(主机和端口与请求 Host 一致)。两种来源头都没有的原生客户端不受此校验 |
403 FORBIDDEN |
| API + Bearer 令牌 | 不做来源校验;令牌本身就是凭证 | — |
| 跨域浏览器请求 | 默认不发送任何 CORS 头;只有配置了 CORS_ORIGINS(以及 PUBLIC_BASE_URL 的源)才会被允许 |
浏览器拦截;服务端不会补 Access-Control-Allow-Origin |
因此:网页同源 fetch 可以自动带 Cookie,但写操作仍应带同源来源头;原生 App 使用 Bearer 时无需处理 CSRF;不要把网页的 _csrf 当作 API 参数。