REST API认证
REST API认证
本节介绍 TimeTagger REST API 的认证机制,包括生成 API 令牌、保护请求以及在 Node-RED 流程中处理认证。学习完本节后,您将能够:
- 理解 TimeTagger 的 API 令牌认证模型
- 生成和管理 API 令牌
- 在 HTTP 请求中实现基于令牌的认证
- 排查常见的认证问题
开始本节前,请确保您已完成:
- TimeTagger 已安装并运行(参见 05-05)
- Node-RED 可访问并已配置
- 基本了解 HTTP 头部
- TimeTagger 管理员凭据
TimeTagger 使用简单的基于令牌的认证系统:
客户端请求 → 包含令牌 → 服务器验证 → 授予/拒绝访问与 OAuth 或 JWT 不同,TimeTagger 令牌:
- 不过期(除非手动撤销)
- 是单个字符串(无刷新令牌流程)
- 授予完整 API 访问权限(无作用域/权限级别)
- 绑定到用户账户(管理员或普通用户)
对 IoT 系统的优势:
| 特性 | 好处 |
|---|---|
| 无过期 | 令牌可硬编码到 ESP32/Node-RED 中 |
| 无刷新流程 | 简化了微控制器上的实现 |
| 单令牌 | 一个令牌用于所有 API 操作 |
| 可撤销 | 通过重新生成令牌来禁用访问 |
API 端点基础
Section titled “API 端点基础”所有 API 请求使用以下基础 URL:
http://<服务器地址>:8820/api/v2/示例端点:
| 端点 | 方法 | 用途 |
|---|---|---|
/api/v2/info | GET | 服务器信息 |
/api/v2/records | GET | 获取记录 |
/api/v2/records | POST | 创建新记录 |
/api/v2/records | PUT | 更新现有记录 |
/api/v2/records | DELETE | 删除(隐藏)记录 |
步骤 1:获取 API 令牌
Section titled “步骤 1:获取 API 令牌”Web UI 方法:
1. 登录 TimeTagger Web UI(http://localhost:8820)2. 点击您的用户名(右上角)3. 从下拉菜单中选择"账户"4. 找到"API 令牌"部分5. 复制令牌字符串
┌─────────────────────────────────────┐│ 账户设置 │├─────────────────────────────────────┤│ 用户名:admin ││ ││ API 令牌 ││ ┌─────────────────────────────┐ ││ │ eyJhbGciOiJIUzI1NiIs... │ ││ └─────────────────────────────┘ ││ [复制] [重置令牌] ││ ││ API 令牌允许第三方应用访问 ││ 服务器。令牌不过期。 ││ 重置令牌将撤销所有应用 ││ 的访问权限。 │└─────────────────────────────────────┘API 方法(如果已认证):
# 使用现有令牌的 curl 命令curl -s http://localhost:8820/api/v2/info \ -H "Authorization: Bearer 您的_TOKEN"步骤 2:验证 API 令牌
Section titled “步骤 2:验证 API 令牌”在 Node-RED 中使用前测试令牌:
# 使用 curl 测试curl -s -X GET "http://localhost:8820/api/v2/info" \ -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIs..."
# 预期响应(成功):# {"ok":true,"version":"24.12","user":"admin",...}
# 预期响应(失败):# {"ok":false,"error":"Unauthorized"}步骤 3:在 Node-RED 中配置认证
Section titled “步骤 3:在 Node-RED 中配置认证”Node-RED 函数节点用于认证:
// auth-config.js — 放置在 Function 节点中// 配置 TimeTagger API 请求的认证信息
const authToken = "eyJhbGciOiJIUzI1NiIs..."; // 替换为您的实际令牌
msg.headers = { "Authorization": "Bearer " + authToken, "Content-Type": "application/json"};
return msg;可重用的认证模块:
创建子流程或使用全局上下文以获得更清晰的代码:
// 在函数节点中,全局设置一次认证令牌if (!global.get("timetaggerAuth")) { global.set("timetaggerAuth", { token: "eyJhbGciOiJIUzI1NiIs...", baseUrl: "http://timetagger:80/api/v2" });}步骤 4:安全存储令牌
Section titled “步骤 4:安全存储令牌”为达到环境级别的安全性,将令牌存储在 Docker 环境变量中:
Docker Compose 方法:
services: nodered: image: nodered/node-red:latest environment: - TIMETAGGER_TOKEN=eyJhbGciOiJIUzI1NiIs... - TIMETAGGER_URL=http://timetagger:80/api/v2读取环境变量的 Node-RED 流程:
// 在启动时的函数节点中const token = process.env.TIMETAGGER_TOKEN;const url = process.env.TIMETAGGER_URL;
if (token && url) { global.set("timetaggerAuth", { token: token, baseUrl: url }); node.warn("已从环境变量配置 TimeTagger 认证");} else { node.error("环境中未配置 TimeTagger 认证");}步骤 5:认证错误处理
Section titled “步骤 5:认证错误处理”为认证失败实现适当的错误处理:
// 在 HTTP 请求节点之后使用,处理 401 响应
if (msg.statusCode === 401) { node.warn("TimeTagger 认证失败 - 请检查 API 令牌"); msg.authError = true; msg.errorDetail = "令牌无效或已过期。请在 TimeTagger 账户设置中重新生成。";} else if (msg.statusCode === 403) { node.warn("TimeTagger 访问被拒绝"); msg.authError = true; msg.errorDetail = "令牌没有足够的权限。";} else if (msg.statusCode >= 400) { node.warn("TimeTagger HTTP 错误:" + msg.statusCode); msg.authError = true; msg.errorDetail = "HTTP " + msg.statusCode;}
return msg;验证认证是否正常工作:
# 1. 使用正确令牌测试curl -s -X GET "http://localhost:8820/api/v2/info" \ -H "Authorization: Bearer 有效令牌"
# 预期:包含用户信息的 JSON# {"ok":true,"version":"24.12","user":"admin"}
# 2. 使用无效令牌测试curl -s -X GET "http://localhost:8820/api/v2/info" \ -H "Authorization: Bearer 无效令牌"
# 预期:401 未授权# {"ok":false,"error":"Unauthorized"}
# 3. 不带令牌测试curl -s -X GET "http://localhost:8820/api/v2/info"
# 预期:401 未授权# {"ok":false,"error":"Unauthorized"}Node-RED 测试流程:
[注入] → [函数:设置认证头] → [HTTP 请求] → [调试] ↓ [http://localhost:8820/api/v2/info]- 创建一个 Inject 节点(时间戳触发)
- 创建一个 Function 节点,包含认证头代码
- 创建一个 HTTP Request 节点(GET 到
/api/v2/info) - 连接到 Debug 节点
- 部署并触发
预期的调试输出:
{ "ok": true, "version": "24.12", "user": "admin", "now": 1715942400, "from_epoch": 0, "to_epoch": 0}问题 1:令牌无法使用
Section titled “问题 1:令牌无法使用”症状:尽管使用了正确的令牌,HTTP 401 仍然存在
可能原因:
- 令牌包含多余的空白字符
- 令牌已重置/重新生成
- 使用了来自不同实例的令牌
解决方案:
# 1. 在 TimeTagger 账户设置中重新生成令牌# 2. 精确复制令牌(无前导/尾随空格)# 3. 使用新令牌更新所有应用
# 逐字符测试令牌echo -n "您的_TOKEN" | wc -c问题 2:CORS 错误
Section titled “问题 2:CORS 错误”症状:从 Node-RED 调用 API 时浏览器控制台显示 CORS 错误
原因:TimeTagger 的 CORS 策略阻止跨域请求
解决方案: 使用 Node-RED 服务器端 HTTP 请求节点(而非基于浏览器)或配置代理:
// 始终使用 Node-RED 的 http-request 节点(服务器端)// 不要使用浏览器的 fetch() 或 XMLHTTPRequest问题 3:令牌泄露
Section titled “问题 3:令牌泄露”症状:在日志或错误消息中可见令牌
解决方案:
// 在日志输出中对令牌进行脱敏处理function sanitize(str) { if (str && str.length > 10) { return str.substring(0, 6) + "..." + str.substring(str.length - 4); } return str;}
node.warn("使用令牌:" + sanitize(authToken));// 输出:"使用令牌:eyJhb...Is..."- ✅ 建议:将 API 令牌存储在环境变量中,而非流程代码中
- ✅ 建议:在生产部署中使用 Docker secrets
- ✅ 建议:定期重新生成令牌(如每 6 个月)
- ❌ 避免:在 GitHub 仓库或共享流程中硬编码令牌
- ❌ 避免:在不同环境(开发/测试/生产)之间共享令牌
- TimeTagger 使用简单的令牌认证——没有 OAuth,没有过期
- API 令牌从 TimeTagger Web UI 的账户设置中获取
- 令牌通过 Authorization 头部传递:
Bearer <令牌> - Node-RED 可以使用环境变量实现安全的令牌存储
- 401 响应表示令牌问题——如果需要请重新生成