Excalidraw 与 LDAP 集成:打造企业级可信协作白板
在一家中型科技公司,开发团队正使用 Excalidraw 进行系统架构设计。某天,一位已离职员工的账户仍能访问敏感架构图——原因很简单:他们用的是匿名实例,没人记得去手动删除账号。这并非个例。随着远程协作成为常态,轻量工具的安全短板逐渐暴露。如何让一个“随手画”的白板,具备企业级身份管控能力?答案是:通过 LDAP 实现集中认证。
Excalidraw 本身并不内置用户管理系统,更不支持直接对接目录服务。但它的灵活性恰恰在于此——它不强制任何认证方式,而是将身份判断交给前置层处理。这种“信任代理”的设计哲学,为集成 LDAP 提供了天然接口。真正的挑战不在代码本身,而在于架构的合理编排:谁来验证身份?如何传递上下文?怎样确保安全不失控?
架构核心:反向代理作为认证枢纽
我们不必修改 Excalidraw 源码,也不需要在其容器内运行 LDAP 客户端。正确的做法是,在其前端部署一个具备认证能力的反向代理,比如 Nginx 结合自定义认证模块或成熟的身份网关(如 Authelia、Keycloak)。这个代理就像一道安检门,所有请求必须先通过身份核验,才能进入后端应用。
graph LR A[用户浏览器] --> B[反向代理] B --> C{已认证?} C -->|否| D[重定向至登录页] C -->|是| E[Excalidraw 服务] D --> F[LDAP 服务器验证凭据] F --> G[签发 JWT] G --> B B --> E E --> H[解析 JWT 加载画布]在这个流程中,Excalidraw 只做一件事:信任来自代理的Authorization头部,并验证其中的 JWT 是否合法。这意味着你可以完全剥离应用层的身份逻辑,专注于协作功能本身。
实现路径:从登录到令牌的闭环
假设你已有一个运行中的 OpenLDAP 或 Active Directory 实例,接下来的关键是如何打通这条链路。
第一步:配置反向代理拦截未认证请求
以 Nginx 为例,你可以设置一条规则,当请求未携带有效凭证时,重定向至/login:
location / { auth_request /auth-jwt; proxy_pass http://excalidraw-backend; proxy_set_header X-Forwarded-User $upstream_http_x_forwarded_user; } location = /auth-jwt { internal; proxy_pass http://auth-service/verify; proxy_pass_request_body off; proxy_set_header Content-Length ""; proxy_set_header X-Original-URI $request_uri; }这里的/auth-jwt是一个内部校验端点,由你的认证服务实现。如果返回 200,则放行;否则拒绝。
第二步:构建 LDAP 认证服务
认证服务的核心任务是接收用户名密码,连接 LDAP 服务器完成绑定操作。Node.js 是一个理想选择,得益于ldapjs库的成熟支持。
const ldap = require('ldapjs'); const jwt = require('jsonwebtoken'); const client = ldap.createClient({ url: process.env.LDAP_URI, tlsOptions: { rejectUnauthorized: true } }); async function handleLogin(req, res) { const { username, password } = req.body; const userDN = `uid=${username},ou=People,dc=example,dc=com`; try { // 先用管理员账号绑定,确认用户存在 await bindAsAdmin(); const entry = await searchUser(userDN); if (!entry) { return res.status(401).json({ error: 'Invalid credentials' }); } // 再尝试以用户身份绑定(实际认证) const userClient = ldap.createClient({ url: process.env.LDAP_URI }); await new Promise((resolve, reject) => { userClient.bind(userDN, password, (err) => { if (err) return resolve(false); resolve(true); }); }); // 成功则签发 JWT const token = jwt.sign( { sub: username, name: entry.object.cn }, process.env.JWT_SECRET, { expiresIn: '4h' } ); res.cookie('token', token, { httpOnly: true, secure: true, sameSite: 'lax' }).redirect('/'); } catch (err) { res.status(500).json({ error: 'Authentication service error' }); } }这段代码看似简单,实则隐藏多个工程细节:
- 连接复用:频繁创建 LDAP 客户端会导致连接风暴,应使用连接池或保持长连接;
- 输入过滤:
username必须经过白名单校验,防止构造恶意 DN(如uid=john);|(objectClass=*); - 错误模糊化:统一返回“凭证无效”,避免泄露账户是否存在;
- 证书管理:生产环境必须配置 CA 证书,禁用
rejectUnauthorized: false。
第三步:Excalidraw 启用 JWT 模式
回到最初的 Docker Compose 配置,关键在于启用 JWT 支持并关闭匿名访问:
version: '3.8' services: excalidraw: image: excalidraw/excalidraw:latest environment: - ALLOW_ANONYMOUS=false - AUTHENTICATION=json-web-token - JWT_SECRET=your-secure-secret-key ports: - "8080:80"此时,Excalidraw 会检查每个请求的Authorization: Bearer <token>或 Cookie 中的 JWT,并自动提取用户信息用于协作标识。WebSocket 连接也将基于该身份广播操作事件。
安全加固:不只是“能用”,更要“可靠”
很多团队在完成基本集成后就止步于此,殊不知真正的风险才刚刚浮现。
最小权限原则必须落地
用于查询用户的 Bind DN 不应拥有写权限。例如,在 OpenLDAP 中,可为其分配仅读ou=People的 ACL:
access to dn.regex="ou=People,dc=example,dc=com" by dn="cn=ldap-reader,dc=example,dc=com" read by * none这样即使认证服务被攻破,攻击者也无法篡改目录数据。
会话生命周期需精细控制
JWT 一旦签发便不可撤销,这是无状态认证的代价。应对策略包括:
- 设置较短过期时间(建议 1~8 小时);
- 引入 Redis 缓存活跃会话,支持主动登出;
- 对高敏感房间启用二次验证(如编辑前输入 MFA 码)。
容灾与可观测性不可忽视
LDAP 服务器宕机怎么办?完全阻断访问可能影响生产力。一种折中方案是启用“降级只读模式”:允许已登录用户查看内容,但禁止新建或编辑。同时记录日志告警,通知运维快速恢复。
监控方面,建议采集以下指标:
- 每分钟认证请求数
- 成功率与失败率分布
- LDAP 响应延迟 P95/P99
- 异常 IP 登录尝试次数
这些数据接入 Prometheus + Grafana 后,可实现可视化追踪。
超越登录:迈向动态授权体系
当你完成了基础认证,下一步可以思考更深层的价值:基于 LDAP 属性实现细粒度访问控制。
例如,你想让只有“架构师组”的成员才能编辑核心系统拓扑图。LDAP 中有这样的结构:
cn=architects,ou=Groups,dc=example,dc=com member: uid=john.doe,ou=People,dc=example,dc=com你可以在签发 JWT 时,额外查询用户所属组,并加入声明:
{ "sub": "john.doe", "groups": ["engineers", "architects"] }然后在 Excalidraw 前端插件或后端中间件中解析该字段,决定是否允许保存操作。虽然 Excalidraw 原生不支持房间级权限,但你可以通过 URL 路径映射策略实现类似效果:
/room/core-architecture→ 仅architects组可写/room/team-sprint→ 所有engineers组成员可编辑
未来还可对接 SCIM 协议,实现用户生命周期自动化同步——入职即开通权限,离职自动禁用,彻底告别手工维护。
写在最后:工具的价值由架构定义
Excalidraw 很简单,但它不该停留在“够用就行”的层面。在一个重视数据合规与安全治理的企业里,哪怕是最轻量的应用,也必须纳入统一身份体系。
这场集成的本质,不是给白板加个登录框,而是重新思考:如何让开源工具真正融入企业基础设施。它考验的不仅是技术实现,更是对安全边界、运维效率和用户体验的整体权衡。
当你看到团队成员用公司账号一键登录,绘制的每一条线都能追溯到真实身份,且权限随组织架构自动更新时,你会发现——那个曾经“只是画画”的工具,已经悄然进化为知识协作的信任节点。而这,正是现代工程实践应有的样子。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考