Bedrud 支持多种认证方式。
JWT(JSON Web Tokens)
Bedrud 使用 JWT 进行会话管理。登录时,服务器返回两个令牌:
- Access Token: 短期有效(例如 1 小时)。用于访问受保护的 API 端点。
- Refresh Token: 长期有效(例如 30 天)。用于在无需重新登录的情况下获取新的 Access Token。
后端在 internal/middleware/auth.go 文件中验证这些令牌。
令牌管理与安全性
1. 令牌对策略(Rotation)
Bedrud 使用安全的令牌轮换策略。用户认证时,会收到:
- Access Token: 使用 HS256 签名,包含用户 ID、名称和权限。有效期较短(通过
tokenDuration配置)。 - Refresh Token: 一个独立的长期令牌。
轮换机制: 当 Access Token 过期时,客户端将 Refresh Token 发送到 /api/auth/refresh。服务器随后签发一对全新的令牌,并更新数据库中存储的 refresh token。即使令牌被盗,这也限制了可利用的时间窗口。
2. 令牌撤销(Blacklisting)
为了支持安全的登出,Bedrud 实现了令牌黑名单。
- 当用户登出时,其当前的 Refresh Token 会被添加到
blocked_refresh_tokens表中。 - 在刷新任何会话之前,服务器会检查此表。如果令牌已被阻止,请求将立即被拒绝。
- 后台任务(Scheduler)负责在这些被阻止的令牌自然过期后进行清理。
3. JWT Claims 结构
令牌携带元数据,允许后端和前端无需查询数据库即可快速做出决策:
{
"userId": "uuid-string",
"email": "user@example.com",
"name": "Display Name",
"accesses": ["user", "admin"],
"exp": 123456789,
"iat": 123456780
}认证方式
1. 邮箱密码登录
- 密码使用 bcrypt 进行哈希处理—从不以明文存储。
- 注册时,会在数据库中创建新的用户记录。
2. 社交登录(OAuth2)
Bedrud 使用 Goth 库支持:
- GitHub
你可以在 config.yaml 中填写 auth: 部分的 Client ID 和 API Secret 来启用它们。
3. Passkeys(WebAuthn/FIDO2)
Bedrud 通过 FIDO2 标准(WebAuthn)支持无密码认证。
- 注册流程:
- 开始: 服务器生成一个加密安全的 Challenge 并将其存储在用户会话中。
- 完成: 客户端的 authenticator(如 TouchID、YubiKey)对 challenge 进行签名。服务器验证 attestation,提取公钥,并将其保存在
passkeys表中。
- 认证流程:
- 开始: 服务器签发一个新的 challenge。
- 完成: 客户端使用私钥对 challenge 进行签名。服务器从数据库中检索公钥,验证签名,并检查签名计数器。
- 安全性:
Counter字段的匹配可以防止重放攻击。如果 authenticator 的计数器不高于存储的计数器,则登录将被拒绝。
4. 访客登录
允许用户仅通过输入名称即可立即加入会议。服务器创建一个具有 guest 角色的临时用户记录。
电子邮件验证
当配置中 requireEmailVerification: true 时,本地(非OAuth)注册和登录需要电子邮件确认:
- 注册 创建用户但将
EmailVerifiedAt设置为nil。用户必须验证后才能登录。 - 登录 对未验证账户返回
403及{"requiresVerification": true}。 - 重新发送 通过
POST /api/auth/verify/resend— 受verificationEmailCooldownMins和单独的速率限制桶(authResendMaxRequests)限制。 - 自动清理 在
unverifiedAccountTTLHours(默认48小时,0为禁用)后删除未验证账户。 - 修改邮箱 触发新的验证流程。用户保持登录状态;颁发新令牌。
访客用户例外——他们没有电子邮件。
密码重置
密码重置流程(需要SMTP):
POST /api/auth/forgot-password带上{"email": "..."}— 服务器发送重置链接到邮箱POST /api/auth/reset-password带上{"token": "...", "newPassword": "..."}— 设置新密码
重置令牌TTL由 resetTokenTTLHours 控制(默认1小时)。forgot-password端点共享认证速率限制桶。
冷却与速率限制
Bedrud 使用四个独立的速率限制桶:
| 桶 | 端点 | 默认值 | 窗口 |
|---|---|---|---|
| 认证 | login, register, refresh, passkey, forgot-password | 10 | 60s |
| 访客 | guest-login | 5 | 60s |
| API | 通用API | 30 | 60s |
| 重新发送 | verify/resend | 3 | 60s |
桶设置为 0 = 禁用。所有限制按远程IP计算。超出限制的请求返回 429 Too Many Requests 及 Retry-After 头部。
互操作性与 CORS
Bedrud 设计为可从多个来源访问,这对于开发环境(React 开发服务器)和生产环境(不同子域名)至关重要。
- CORS 策略: 在
config.yaml中定义。它支持AllowCredentials: true,这是 OAuth 和 Passkey 流程中使用的会话 cookie 所必需的。 - 允许的来源: 默认情况下,允许服务器自身的域名和
localhost:3000(React 开发服务器端口)。
用户角色(访问控制)
每个用户都有一个 accesses 数组,可以同时包含多个访问级别。JWT claims 中包含完整的 accesses 数组,允许中间件检查细粒度权限。
访问级别
| 访问级别 | 范围 | 授予权限 |
|---|---|---|
superadmin | 系统级 | 完整访问管理仪表板(/dashboard/admin)、所有管理 API endpoint(/api/admin/*)、用户管理、房间管理、系统设置、邀请令牌。作为所有房间管理操作的全局绕过。由 RequireAccess("superadmin") 中间件保护。 |
admin | 已定义,未强制执行 | 可在 accesses 数组中使用,但当前未被任何中间件使用。仅用于信息标识。保留用于未来的基于角色的访问控制功能。 |
moderator | 房间级 | 可在特定房间内进行管理:禁言聊天、关闭/开启参与者音频、聚光灯、停止屏幕共享、禁用视频。由房间创建者或 superadmin 在通话中通过 PromoteParticipant 提升。通过 isRoomModerator() 辅助函数检查。 |
user | 标准 | 所有注册用户的默认级别。可创建房间、加入房间、管理个人资料和管理自己的通行密钥。由 Protected() 中间件保护。 |
guest | 受限 | 用于通过访客登录加入公共房间的临时用户。无法创建房间或访问受保护的功能。 |
角色层级
superadmin > admin > moderator > user > guest
superadmin 可以在任意房间中执行任何管理操作,而无需被提升为房间 moderator。房间创建者自动成为房间管理员,并可将参与者提升为 moderator。
角色分配
角色通过多种渠道管理:
- CLI:
bedrud user create(创建为user)、bedrud user promote(添加superadmin)、bedrud user demote(移除superadmin) - 管理仪表板: 用户详情页面有提升/降级按钮
- 管理 API:
PUT /api/admin/users/:id/accesses,携带所需的accesses数组 - 会议中: 房间创建者可将参与者提升为房间级 moderator
注意: 没有用于创建首个 superadmin 的 API endpoint 或 Web UI。安装后,您必须使用 CLI(
bedrud user create+bedrud user promote)来引导初始管理员访问。这是一项有意的安全措施。