🔐 通过正确构建来学习认证。一个可扩展、符合标准的参考实现,适用于 Cloudflare Workers,使用 Hono、Turso、PBKDF2 和 JWT 双令牌会话。
演示说明: 登录端点受自适应 PoW 挑战保护——重复失败会返回更高的工作量证明难度。基于缓存的速度限制已实现并测试,但当前未在在线演示中启用;翻转
app.ts中的createCacheClient(位于apps/cloudflare-workers/src/app.ts)可激活它。
一个从零开始为 Cloudflare Workers 构建的认证参考实现——PBKDF2 密码哈希、JWT 双令牌会话、常量时间比较、滑动过期和可移除的可观测性插件——全部通过 Hono、Turso(可选 Valkey/Redis 缓存)和严格的 TypeScript 集成。
每个设计选择都追溯到一个标准:NIST SP 800-63B 用于凭证,NIST SP 800-132 用于密钥派生,OWASP ASVS 用于验证,以及 RFC 8725 用于 JWT 最佳实践。
正在发布产品? 请改用 Better Auth——它自带 OAuth、通行密钥、多因素认证、速率限制等功能,并拥有活跃的插件生态。此仓库旨在教你认证如何工作,而非替代生产级库。
本项目有意省略了超出其教学范围的功能。如果你正在将此代码扩展为生产用途(或评估生产认证系统所需),下表按优先级整理了缺口。
对于大多数实际项目,请使用 Better Auth 而非自行构建。
| 功能 | 为何重要 | 标准 / 参考 |
|---|---|---|
| 泄露密码检查 | 防止使用已知在公开泄露数据中的密码 | NIST SP 800-63B §5.1.1.2、HIBP API |
所有这些都是选择 Better Auth 的绝佳理由。
.
├── apps/
│ └── cloudflare-workers/ # 示例 Worker + Hono 路由
├── packages/
│ ├── core/ # 认证服务、中间件、加密工具
│ ├── infrastructure/ # 数据库客户端 + 工具
│ ├── observability/ # 事件发射、自适应挑战、操作 API(可移除插件)
│ ├── schemas/ # Zod schemas
│ └── types/ # 共享 TypeScript 类型
├── tools/
│ └── cli/ # plctl — 用于 /ops 接口的 Go TUI
└── docs/
├── adr/ # 架构决策记录
└── audits/ # 安全审计
git clone https://github.com/vhscom/private-landing.git
cd private-landing
bun install
bun run dev
就是这样——无需账户、无需 API 密钥、无需 .env 文件。开发服务器以本地 SQLite 数据库和生成的密钥启动。打开 http://localhost:8788 注册账户并探索认证流程。
有 Turso 账户? 在
apps/cloudflare-workers/中放置一个.dev.vars文件(参见.dev.vars.example),然后bun run dev将自动使用 wrangler 连接你的远程数据库。使用bun run dev:local可强制使用本地服务器。
参见 CONTRIBUTING.md 获取测试和部署说明。
此仓库包含一个 CLAUDE.md 文件,为 AI 助手提供上下文。使用 Claude Code、Cursor 或类似 AI 驱动的开发工具时:
CLAUDE.md 以获取项目上下文docs/adr/ 中的架构决策记录解释了设计选择docs/audits/ 中的安全审计记录了安全态势代码库设计为 AI 可读,具有清晰的模块边界、全面的类型和描述性命名。
| 层 | 功能 |
|---|
| 密码存储 | 使用 128 位盐值的 PBKDF2-SHA384、完整性摘要、版本追踪(password-service.ts) |
| 会话管理 | 服务端会话,带设备追踪、滑动过期、每个用户最多 3 个会话的强制限制;通过 Valkey/Redis 的可选缓存会话(session-service.ts、cached-session-service.ts) |
| 密码更改 | 当前密码重新验证、完整 PBKDF2 重新哈希、所有会话原子撤销(account-service.ts、ADR-004) |
| JWT 双令牌模式 | 15 分钟访问令牌 + 7 天刷新令牌,与会话关联以实现撤销(token-service.ts) |
| 认证中间件 | 自动刷新流程、显式 HS256 固定、typ 声明验证(require-auth.ts) |
| 安全 Cookie | HttpOnly、Secure、SameSite=Strict、Path=/(cookie.ts) |
| 安全头部 | HSTS、CSP、CORP/COEP/COOP、Permissions-Policy、指纹移除(security.ts) |
| 输入验证 | 使用 Zod schema,采用符合 NIST 的密码策略(仅长度限制,无复杂度规则) |
| 速率限制 | 固定窗口限流,防止暴力破解和凭据填充攻击:对公共认证路由(如登录)按 IP 限流,对受保护操作按用户限流;无硬锁定(符合 NIST)(ADR-006) |
| 可观测性插件 | 结构化安全事件、自适应 PoW 挑战、代理认证的 /ops API——通过中间件接入,删除一个包即可移除(ADR-008) |
| CLI 工具 | Go TUI (plctl),用于查询事件、管理会话和通过 /ops 接口供应代理凭证(tools/cli/) |
| 攻击向量测试 | JWT 篡改、算法混淆、类型混淆、Unicode 边界情况、信息泄露检查 |
| 功能 | 为何重要 | 标准 / 参考 |
|---|
| CSRF 保护(如果 SameSite 放松) | 目前 SameSite=Strict 可防止 CSRF;如果出于用户体验考虑更改为 Lax,则需要显式令牌 | OWASP CSRF 备忘单 |
| 刷新令牌轮换 | 检测令牌窃取——如果旋转出去的刷新令牌被重放,则撤销整个会话族 | RFC 6819 §5.2.2.3 |
JWT 中的 aud 声明 | 防止一个服务的令牌被共享同一密钥的其他服务接受 | RFC 7519 §4.1.3、RFC 8725 §3.9 |
| 内联脚本的 CSP nonce | 当前 CSP 使用 'unsafe-inline';nonce 消除了内联脚本 XSS 向量 | MDN CSP script-src |
| 功能 | 为何重要 | 标准 / 参考 |
|---|
| TOTP 多因素认证 | 为高价值账户添加第二个因素 | RFC 6238、NIST SP 800-63B §5.1.4 |
| WebAuthn / 通行密钥 | 使用平台身份验证器提供抗钓鱼认证 | WebAuthn Level 2 |
| OAuth / 社交登录 | 减少摩擦,避免密码疲劳 | RFC 6749 |
| 魔术链接 / OTP | 低风险流程的无密码选项 | NIST SP 800-63B §5.1.3 |
| 会话分析 | 设备追踪、并发会话可见性、异常检测 | OWASP 会话管理备忘单 |
| 签名密钥轮换 | 允许周期性密钥旋转而无需使所有会话失效 | RFC 7517 (JWK) |
| 功能 | 为何重要 | 标准 / 参考 |
|---|
| DPoP / 令牌绑定 | 将令牌绑定到客户端的 TLS 连接,防止泄露重放 | RFC 9449 (DPoP) |
| 多租户 | 按租户隔离用户池、密钥和策略 | 应用特定 |
| 地理围栏 / IP 声誉 | 阻止来自非预期区域或已知不良 IP 的登录 | OWASP ASVS v5.0 §6.3.5 |
| 自适应认证 | 基于风险信号(设备、位置、行为)升级认证要求 | NIST SP 800-63B §6 |
| PBKDF2 迭代升级或 Argon2id | OWASP 建议 210,000 次 PBKDF2-SHA512 迭代(Cloudflare 限制为 100k);Argon2id 是内存密集型 | OWASP 密码存储备忘单 |