Databunker 0.8.37 API 使用详解
Databunker 0.8.37 REST API 全端点实测:用户记录、应用数据、会话、验证码登录、GDPR 合规工作流、审计与分享记录,含错误码速查与排障实录。
Databunker 0.8.37 API 使用详解
Databunker 没有富 CLI,所有能力都收敛在一套 REST API 上——本文按域逐个实测:用户记录、应用数据、会话、验证码登录、同意与合规工作流、审计、分享记录、到期删除,并给出错误码速查与两个高频踩坑实录。所有请求与回显均为真实执行记录。
一、通用约定
| 项 | 值 |
|---|---|
| Base URL | http://localhost:3000(官方默认;本文实验环境映射在 8134,下文命令以实测值为准) |
| 认证头 | X-Bunker-Token: <令牌> |
| 请求体 | JSON(Content-Type: application/json);也接受表单编码 |
| 响应 | 统一 JSON,status 为 ok/error |
| 安全响应头 | 每个响应固定携带 CSP、HSTS、X-Content-Type-Options: nosniff、X-Frame-Options: SAMEORIGIN、XSS 防护头(见第八节实测头表) |
| CORS | 全放开:Access-Control-Allow-Origin: *,预检返回 204(第八节实测) |
令牌注入方式(示例值均为本文实验自造,生产请按《Databunker 0.8.37 Docker Compose 部署指南》第四节重新生成):
# 根令牌来自初始化时的 env 文件
export ROOT=$(grep DATABUNKER_ROOTTOKEN .env/databunker-root.env | cut -d= -f2)
# 之后所有管理面请求: -H "X-Bunker-Token: $ROOT"
令牌种类:
| 种类 | 来源 | 作用域 |
|---|---|---|
| 根令牌(root) | -init 时由 DATABUNKER_ROOTTOKEN 提供 | 全部管理面 API |
| 临时令牌(xtoken) | 验证码登录流程换取 | 仅本人记录(实测越权访问返回 403) |
| 用户 token | 创建记录返回的 UUID | 标识记录用,不是凭据 |
健康检查:GET /v1/status 返回纯文本 OK(无需令牌,镜像内置探活即用此端点)。
二、用户记录 CRUD(核心域)
2.1 创建
curl -s -X POST http://localhost:8134/v1/user \
-H "X-Bunker-Token: $ROOT" -H 'Content-Type: application/json' \
-d '{"first":"John","last":"Doe","login":"api.d5","email":"api.d5@example.com","phone":"+441234567891","password":"q1w2e3r4","custom":"d5vip"}'
{"status":"ok","token":"da58bc19-ce07-07b0-be2f-cc0ebb6b9c19"}
字段完全自由(任意 JSON 键均可入库),但 4 个键参与唯一索引:login、email、phone、custom。重复值直接拒绝:
curl -s -X POST http://localhost:8134/v1/user -H "X-Bunker-Token: $ROOT" \
-H 'Content-Type: application/json' -d '{"login":"api.d5b","custom":"d5vip"}'
{"status":"error","message":"duplicate index: custom"}
curl -s -X POST http://localhost:8134/v1/user -H "X-Bunker-Token: $ROOT" \
-H 'Content-Type: application/json' -d '{"email":"api.d5@example.com"}'
{"status":"error","message":"duplicate index: email"}
custom 的语义是"业务自定义唯一引用"(如内部客户号),实测与 login/email/phone 同级去重。
匿名创建:官方默认配置 create_user_without_access_token: true,不带任何令牌也能建档(面向注册场景):
curl -s -X POST http://localhost:8134/v1/user -H 'Content-Type: application/json' -d '{"email":"anon.d5@example.com"}'
{"status":"ok","token":"97406150-112f-902e-e9e2-0d72019e9521"}
内部系统请在 YAML 关闭该开关(见《Databunker 0.8.37 配置参数详解》5.1 节)。
2.2 检索:五种定位方式
GET /v1/user/:mode/:identity,mode ∈ token | login | email | phone | custom:
curl -s -H "X-Bunker-Token: $ROOT" http://localhost:8134/v1/user/login/api.d5
{"status":"ok","token":"da58bc19-ce07-07b0-be2f-cc0ebb6b9c19","data":{"custom":"d5vip","email":"api.d5@example.com","first":"John","last":"Doe","login":"api.d5","password":"q1w2e3r4","phone":"+441234567891"}}
按 email/token 检索回显相同;电话检索需归一化——入库 +441234567891,查询用国际格式去加号补零:
curl -s -H "X-Bunker-Token: $ROOT" http://localhost:8134/v1/user/phone/00441234567891
{"status":"ok","token":"da58bc19-ce07-07b0-be2f-cc0ebb6b9c19","data":{...同上...}}
非法 mode 直接拒绝:
curl -s -i -H "X-Bunker-Token: $ROOT" http://localhost:8134/v1/user/invalid/api.d5 | sed -n '1p;$p'
HTTP/1.1 405 Method Not Allowed
{"status":"error","message":"bad mode"}
2.3 修改(PUT,增量合并)
curl -s -X PUT http://localhost:8134/v1/user/token/da58bc19-ce07-07b0-be2f-cc0ebb6b9c19 \
-H "X-Bunker-Token: $ROOT" -H 'Content-Type: application/json' \
-d '{"first":"Johnny","custom":"gold5"}'
{"status":"ok","token":"da58bc19-ce07-07b0-be2f-cc0ebb6b9c19"}
回读确认只动了传入字段(last/email 等保持原值):
curl -s -H "X-Bunker-Token: $ROOT" http://localhost:8134/v1/user/token/da58bc19-ce07-07b0-be2f-cc0ebb6b9c19
{"status":"ok","token":"da58bc19-ce07-07b0-be2f-cc0ebb6b9c19","data":{"custom":"gold5","email":"api.d5@example.com","first":"Johnny","last":"Doe","login":"api.d5","password":"q1w2e3r4","phone":"+441234567891"}}
2.4 删除(被遗忘权)
curl -s -X DELETE http://localhost:8134/v1/user/token/da58bc19-ce07-07b0-be2f-cc0ebb6b9c19 \
-H "X-Bunker-Token: $ROOT"
{"status":"ok","result":"done"}
删除后按 token 仍可读,但 data 为空对象(记录内容被加密擦除,token 行保留占位):
curl -s -H "X-Bunker-Token: $ROOT" http://localhost:8134/v1/user/token/da58bc19-ce07-07b0-be2f-cc0ebb6b9c19
{"status":"ok","token":"da58bc19-ce07-07b0-be2f-cc0ebb6b9c19","data":{}}
级联效果:该用户的 userapp 数据同步不可读:
curl -s "http://localhost:8134/v1/userapp/token/da58bc19-ce07-07b0-be2f-cc0ebb6b9c19/webshop" -H "X-Bunker-Token: $ROOT"
{"status":"error","message":"not found"}
自助删除(forget me):selfservice.forget_me: true 时,用户凭 xtoken 即可 DELETE /v1/user/email/<自己>,实测返回 {"status":"ok","result":"done"}。
2.5 批量列表(默认关闭)
curl -s -X POST http://localhost:8134/v1/users -H "X-Bunker-Token: $ROOT" -H 'Content-Type: application/json' -d '{}'
默认返回 Access denied(HTTP 403)。开启 generic.list_users: true 后返回全量列表,注意 private 字段是 base64 编码明文(编码≠加密),只应作为受控导出通道:
{"status":"ok","total":3,"rows":[{"token":"...","private":"eyJlbWFpbCI6...","active":true},...]}
三、应用数据域 userapps
一条用户记录可挂多个命名应用域(如 webshop 存收货地址),与主记录独立读写:
# 创建
curl -s -X POST "http://localhost:8134/v1/userapp/token/da58bc19-.../webshop" \
-H "X-Bunker-Token: $ROOT" -H 'Content-Type: application/json' \
-d '{"address":"Baker Street 221B","city":"London","country":"UK"}'
{"status":"ok","token":"da58bc19-ce07-07b0-be2f-cc0ebb6b9c19"}
# 读取
curl -s "http://localhost:8134/v1/userapp/token/da58bc19-.../webshop" -H "X-Bunker-Token: $ROOT"
{"status":"ok","token":"da58bc19-ce07-07b0-be2f-cc0ebb6b9c19","data":{"address":"Baker Street 221B","city":"London","country":"UK"}}
PUT 同为增量合并(只传 city 即只改 city):
{"status":"ok","token":"da58bc19-ce07-07b0-be2f-cc0ebb6b9c19"}
# 读回:city 已变,address/country 保留
curl -s "http://localhost:8134/v1/userapp/token/da58bc19-.../webshop" -H "X-Bunker-Token: $ROOT"
{"status":"ok","token":"da58bc19-ce07-07b0-be2f-cc0ebb6b9c19","data":{"address":"Baker Street 221B","city":"Manchester","country":"UK"}}
# 用户的应用域列表 / 全库应用名清单
curl -s "http://localhost:8134/v1/userapps/token/da58bc19-..." -H "X-Bunker-Token: $ROOT"
curl -s http://localhost:8134/v1/userapps -H "X-Bunker-Token: $ROOT"
{"status":"ok","total":1,"rows":[...]}
{"status":"ok","apps":["webshop"]}
主记录检索默认不带应用域数据(GET /v1/user/... 只返回主 data),应用域须显式按名读取。
四、会话 sessions
记录用户设备/会话上下文(IP、UA 等),供审计与风控:
curl -s -X POST "http://localhost:8134/v1/session/108c8ce2-d98b-457c-99dc-3ed688f6f101" \
-H "X-Bunker-Token: $ROOT" -H 'Content-Type: application/json' \
-d '{"login":"api.d5","data":{"ip":"10.0.0.9","agent":"curl"}}'
{"status":"ok","session":"108c8ce2-d98b-457c-99dc-3ed688f6f101"}
读取、列表、删除:
curl -s "http://localhost:8134/v1/session/108c8ce2-..." -H "X-Bunker-Token: $ROOT"
{"status":"ok","session":"108c8ce2-d98b-457c-99dc-3ed688f6f101","when":1793677985,"data":{"data":{"agent":"curl","ip":"10.0.0.9"},"login":"api.d5"}}
curl -s "http://localhost:8134/v1/sessions/token/da58bc19-..." -H "X-Bunker-Token: $ROOT"
{"status":"ok","total":1,"rows":[{"when":1793677985,"session":"108c8ce2-d98b-457c-99dc-3ed688f6f101","data":{"data":{"agent":"curl","ip":"10.0.0.9"},"login":"api.d5"}}]}
curl -s -X DELETE "http://localhost:8134/v1/session/108c8ce2-..." -H "X-Bunker-Token: $ROOT"
{"status":"ok"}
⚠️ 会话与用户的关联靠请求体顶层的
token/login/email/phone字段定位用户,不是user_ref——踩坑过程见第九节实录 1。会话另有policy.max_session_retention_period(默认 1h)自动清理。
五、验证码登录流程(换取 xtoken)
Web 门户/API 共用的登录链路,四步(实测端到端):
5.1 获取验证码串
GET /(门户首页 HTML)内嵌 var captchaCode = "<hex串>"——服务端用主密钥派生的 AES-GCM 密钥加密的"随机6位数字:时间戳",有效期 120 秒:
captcha 串(节选): cf473b17465299f2d41890fe44f5b4c49789604b ...
配套 GET /v1/captcha/:code 返回同数字的 PNG 图(人机校验展示用)。
5.2 prelogin
用户提交身份 + 验证码数字 + captcha 串:
curl -s "http://localhost:8134/v1/prelogin/email/test@securitybunker.io/538072/<captcha串>"
{"status":"ok","result":"done"}
服务端校验 captcha 解密值与提交数字一致后,把一次性登录码发给用户邮箱(SMTP 段配置);演示账号(email=test@securitybunker.io 或 phone=4444)走固定登录码 4444,无需邮件网关。
5.3 login
curl -s "http://localhost:8134/v1/login/email/test@securitybunker.io/4444"
{"status":"ok","xtoken":"b6ce922e-82c4-0b74-d00d-fcdc9ae0648d","token":"377042ed-f0c0-20b0-fb46-c1a0ecf32638"}
xtoken 即该用户的临时访问令牌(存 xtokens 表,受 max_user_retention_period 约束)。
5.4 xtoken 作用域实测
本人可读:
curl -s -H "X-Bunker-Token: b6ce922e-82c4-0b74-d00d-fcdc9ae0648d" \
http://localhost:8134/v1/user/email/test@securitybunker.io
{"status":"ok","token":"377042ed-f0c0-20b0-fb46-c1a0ecf32638","data":{"email":"test@securitybunker.io","first":"Demo","last":"User","phone":"4444"}}
他人记录被拒:
curl -s -i -H "X-Bunker-Token: b6ce922e-82c4-0b74-d00d-fcdc9ae0648d" \
http://localhost:8134/v1/user/login/api.d5 | sed -n '1p;$p'
HTTP/1.1 403 Forbidden
Access denied
六、GDPR 合规域
6.1 法律依据与同意
# 内置法律依据清单(-init 时自动导入 2 条登录相关 consent)
curl -s http://localhost:8134/v1/lbasis -H "X-Bunker-Token: $ROOT"
{"status":"ok","total":2,"rows":[{"basistype":"consent","brief":"core-send-email-on-login","creationtime":1793677208,"fulldesc":"Confirm to allow sending access code using 3rd party email gateway","module":"login","requiredflag":true,"requiredmsg":"This consent is required to give you our service.","shortdesc":"Send email on login","status":"active","usercontrol":true},{"basistype":"consent","brief":"core-send-sms-on-login","creationtime":1793677208,"fulldesc":"Confirm to allow sending access code using 3rd party SMS gateway","module":"login","requiredflag":true,"requiredmsg":"This consent is required to give you our service.","shortdesc":"Send SMS on login","status":"active","usercontrol":true}]}
接受/撤回同意(POST/DELETE /v1/agreement/:brief/:mode/:identity):
curl -s -X POST "http://localhost:8134/v1/agreement/core-send-email-on-login/email/test@securitybunker.io" \
-H "X-Bunker-Token: $ROOT"
{"status":"ok"}
curl -s "http://localhost:8134/v1/agreements/email/test@securitybunker.io" -H "X-Bunker-Token: $ROOT"
{"status":"ok","total":1,"rows":[{"agreementmethod":"api","brief":"core-send-email-on-login","creationtime":1793677996,"endtime":0,"lastmodifiedby":"","mode":"email","starttime":0,"status":"yes","token":"377042ed-f0c0-20b0-fb46-c1a0ecf32638","when":1793677996,"who":"test@securitybunker.io"}]}
brief 不存在时返回 {"status":"error","message":"not found"}——先查 /v1/lbasis 拿合法 brief。
6.2 处理活动(ROPA)
curl -s -X POST http://localhost:8134/v1/pactivity/marketing -H "X-Bunker-Token: $ROOT" \
-H 'Content-Type: application/json' -d '{"name":"Newsletter","purpose":"email marketing","thirdcountry":false}'
{"status":"ok"}
curl -s http://localhost:8134/v1/pactivity -H "X-Bunker-Token: $ROOT"
{"status":"ok","total":1,"rows":[{"activity":"marketing","applicableto":"","briefs":null,"creationtime":1793677997,"fulldesc":"","script":"","title":"marketing"}]}
POST /v1/pactivity/:activity/:brief 可把处理活动与法律依据挂接。
6.3 到期删除(exp)
给用户记录启动"到期删除倒计时",返回 exptoken 供用户点击确认/取消(邮件链接场景):
curl -s -X POST "http://localhost:8134/v1/exp/start/login/api.d5" -H "X-Bunker-Token: $ROOT"
{"status":"ok","exptoken":"5e307433-50f2-ada2-ed9a-f667468b3006"}
curl -s "http://localhost:8134/v1/exp/status/login/api.d5" -H "X-Bunker-Token: $ROOT"
{"status":"ok","exptime":1801713197,"expstatus":"wait","exptoken":"5e307433-50f2-ada2-ed9a-f667468b3006"}
curl -s -X DELETE "http://localhost:8134/v1/exp/cancel/login/api.d5" -H "X-Bunker-Token: $ROOT"
{"status":"ok"}
expstatus 为 wait(倒计时中);到期后由清理任务物理删除。另有 GET /v1/exp/retain/:exptoken(用户挽留)与 GET /v1/exp/delete/:exptoken(立即删除)两个免令牌确认端点。
6.4 可分享记录
生成匿名分享链接(可限定字段与存活时间):
curl -s -X POST "http://localhost:8134/v1/sharedrecord/login/api.d5" -H "X-Bunker-Token: $ROOT" \
-H 'Content-Type: application/json' -d '{"fields":"first,last","ttl":60}'
{"status":"ok","record":"95e5e7b0-2d18-81b8-fae3-4668a16f3cc8"}
任何人(无令牌)按 record id 读取被授权字段:
curl -s http://localhost:8134/v1/get/95e5e7b0-2d18-81b8-fae3-4668a16f3cc8
{"status":"ok","data":{"first":"Johnny","last":"Doe"}}
6.5 DPO 审批工作流
GET /v1/requests(root)与 GET /v1/requests/:mode/:identity 列出用户发起、待审批的 GDPR 请求(删除/变更申请经 Web 门户提交,API 侧提供查询/批准 POST /v1/request/:request/取消 DELETE)。空队列回显:
{"status":"ok","total":0,"rows":[]}
6.6 审计留痕
每次 API 操作自动写入 audit 表(可用 disable_audit 关闭;保留期 max_audit_retention_period 默认 6 个月):
curl -s "http://localhost:8134/v1/audit/list/da58bc19-..." -H "X-Bunker-Token: $ROOT" | head -c 900
{"status":"ok","total":21,"rows":[{"atoken":"b44f71d4-604b-95d7-f86d-b84e708f32fb","identity":"root","mode":"login","more":false,"record":"da58bc19-ce07-07b0-be2f-cc0ebb6b9c19","status":"ok","title":"initiate user record expiration by login","when":1793677997,"who":"api.d5"},{"atoken":"637b83a1-130d-a6df-3717-6ad3616d50f4","identity":"root","mode":"token","more":false,"msg":"generated: 95e5e7b0-2d18-81b8-fae3-4668a16f3cc8","record":"da58bc19-ce07-07b0-be2f-cc0ebb6b9c19","status":"ok","title":"create shareable record by login","when":1793677997,"who":"api.d5"},{"atoken":"f6330382-df37-10b8-77d4-7e5ff65a339c","identity":"root","mode":"login","more":false,"record":"da58bc19-ce07-07b0-be2f-cc0ebb6b9c19","status":"ok","title":"get expiration status by login","when":1793677997,"who":"api.d5"},...]}
每条含 who(身份标识)、identity(令牌角色)、title(操作描述)、record(受影响记录)、when(秒级时间戳)。GET /v1/audit/admin 为全局视图(root 令牌),GET /v1/audit/get/:atoken 按事件取详情。
七、运维端点
- Prometheus 指标:
GET /v1/metrics(root 令牌),标准 Go 运行时指标 + HTTP 直方图:
# HELP go_gc_duration_seconds A summary of the wall-time pause (stop-the-world) duration in garbage collection cycles.
# TYPE go_gc_duration_seconds summary
go_gc_duration_seconds{quantile="0"} 8.9462e-05
go_gc_duration_seconds{quantile="0.25"} 0.000105444
go_gc_duration_seconds{quantile="0.5"} 0.000156904
- 备份:
GET /v1/sys/backup(root 令牌)。实测 PostgreSQL 后端返回HTTP 200, 0 bytes——该端点仅 SQLite 后端有内容,PostgreSQL/MySQL 备份请用pg_dump(见部署指南第十一节)。 - 批量 API(
/v1/bulk/*):默认未挂载,请求返回{"status":"error", "message":"endpoint is missing"}(HTTP 404)。 - 版本:
/databunker/bin/databunker -version→Databunker version: 0.8.37-20261030100830-7667c5056897。
八、CORS 与安全响应头
浏览器直连场景实测预检:
curl -s -i -X OPTIONS http://localhost:8134/v1/user \
-H 'Origin: http://example.com' -H 'Access-Control-Request-Method: POST' \
-H 'Access-Control-Request-Headers: X-Bunker-Token'
HTTP/1.1 204 No Content
Access-Control-Allow-Headers: Accept, Content-Type, Content-Length, Accept-Encoding, X-Bunker-Token
Access-Control-Allow-Methods: POST, PUT, DELETE
Access-Control-Allow-Origin: *
Allow: OPTIONS, POST
Content-Security-Policy: default-src 'self' http: https: data: blob: 'unsafe-inline'
Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-Xss-Protection: 1; mode=block
CORS 为源码硬编码全放开(Allow-Origin: *),无配置项——前端直连时务必自行评估令牌暴露面(浏览器里放 root 令牌等于裸奔,前端场景只应使用登录换取的 xtoken)。
九、错误码速查与排障实录
9.1 错误码速查(全部实测)
| 场景 | HTTP | 响应体 |
|---|---|---|
| 记录不存在 | 405 | {"status":"error","message":"not found"} |
| mode 非法(非 token/login/email/phone/custom) | 405 | {"status":"error","message":"bad mode"} |
| 令牌错误/越权 | 403 | Access denied(纯文本) |
| 唯一索引冲突 | 200 | {"status":"error","message":"duplicate index: <字段>"} |
| 端点不存在/未启用 | 404 | {"status":"error", "message":"endpoint is missing"} |
| 成功写操作 | 200 | {"status":"ok","result":"done"} 或带 token |
注意两处反直觉语义:"记录不存在"用 405 而非 404(源码 ReturnError(..., 405, ...) 统一处理),唯一键冲突 HTTP 仍是 200,调用方必须检查 status 字段。
实录 1:session 创建"成功"却查不到
- 现象:按直觉把用户令牌放在
user_ref字段创建会话,返回{"status":"ok","session":"94d992f3-..."},但GET /v1/sessions/token/<用户>恒为total:0。 - 根因:
sessionCreate只识别请求体顶层的token/login/email/phone来解析用户(源码users_api.go的checkRecord()),user_ref被当作普通业务字段存入密文,用户关联为空。 - 解法:
-d '{"login":"api.d5","data":{...}}'。改用正确姿势后同一查询返回total:1(见第四节回显)。
实录 2:健康检查探错端点
- 现象:按惯例配
GET /health探活,返回 404endpoint is missing。 - 根因:Databunker 健康检查端点是
/v1/status或/status(镜像内置 HEALTHCHECK 即用它),没有/health。 - 解法:探活配置指向
/v1/status,期望 200 +OK。
十、集成建议
- 主库只存 token:业务表加
user_token列引用 Databunker,PII 不落业务库;检索用login/email/phone模式,无需本地索引。 - 令牌分层:服务端持 root 令牌;浏览器/客户端只允许登录换取的 xtoken(403 实测保证越权不可行)。
- 写操作判
status:唯一键冲突返回 200,务必解析 JSON 而非仅看状态码。 - 合规三件套尽早启用:audit(默认开)、
notification_url(事件外推)、policy保留期(默认 3m/6m/1h/1m),对应 GDPR 审计、泄露通知、存储限制义务。 - 官方客户端:Node.js
@databunker/store(npm install @databunker/store,用法见官方 doc/nodejs 页)与 Python 示例(GitHubpython目录)封装了本节全部端点。