ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

Cloudflare OS Slack Gatekeeper 完全指南:基于 Cloudflare Workers 的只读 Slack 工作区安全访问

Cloudflare OS Slack Gatekeeper 完全指南:基于 Cloudflare Workers 的只读 Slack 工作区安全访问 人工智能AI 应用AI AgentAgent 沙箱AI 安全治理【免费下载链接】cloudflare-osAgent workspace built on Cloudflare Workers for creating documents, building apps, and running agents with your company’s context and systems.项目地址https://gitcode.com/gh_mirrors/cl/cloudflare-os点击查看免费下载本篇技术指南以 packages/gatekeeper-slack/README.md 为骨架深入讲解 Cloudflare OS 中Slack gatekeeper的设计与实战它如何以独立的 Cloudflare Worker 运行、通过 OAuth 2.0 用户令牌xoxp-…为 Agent 提供对 Slack 工作区频道、私信、线程、成员、搜索的只读访问以及如何按工作区 / 会话 / 线程三种粒度授权与路由。读完本文你将掌握 Slack 应用的 OAuth 配置要点、三种资源粒度的作用域映射、会话 API 的使用方法以及底层令牌轮换、越权防护与观察者校验的实现原理。一、定位一个只读的 Slack 访问中介Slack gatekeeper 是 Cloudflare OS 中众多 gatekeeper 之一职责是中介mediate一个 Gadget 对用户 Slack 工作区的访问。它的三个核心设计约束是只读绝不发送或修改 Slack 数据源码中以unreachableAction()强制实现见 slack.ts三个 gatekeeper 的applyAction/rejectAction/revertAction均不可达独立 Worker作为自己的 Cloudflare Worker 运行由后端通过GATEKEEPER_SLACK绑定自动发现用户视角使用用户令牌user tokenxoxp-…而非机器人令牌bot token因此 Agent 看到的正是连接用户所能看到的内容——包括私有频道、私信与搜索。从源码结构看该包由slack.tsWorker 入口、OAuth 流程、Durable Object、gatekeeper 实现、slack-api.tsSlack Web API 客户端、types.d.tsAgent 面向的会话 API 类型与configurator/三种授权配置 UI组成依赖gadgets/gatekeeper-kit连接握手、凭据暂存、gadgets/workshop-shared/gatekeepergatekeeper 框架契约与gadgets/configurator-ui配置器 UI 组件。二、认证OAuth 2.0 用户令牌与 Slack 应用配置2.1 为什么用 user tokenREADME 明确指出认证采用 OAuth 2.0通过user_scope请求用户令牌而非机器人令牌。这样 Agent 的访问边界与连接用户完全一致——包括私有频道、直接消息与全局搜索。这一选择也贯穿到令牌交换的实现exchangeAuthCode 在换取授权码时从响应嵌套的authed_user中提取用户令牌、刷新令牌、授权 scope、用户 ID 与团队 ID并在缺少authed_user.access_token时抛出请确保应用请求 user scopeuser_scope的明确错误。2.2 创建 Slack 应用并注入凭据在 Slack 应用管理后台https://api.slack.com/apps创建应用后将客户端凭据注入 Worker 环境变量变量用途CLIENT_IDSlack OAuth 应用客户端 ID生产环境通过 wrangler secrets /.dev.vars注入不写入 wrangler.jsoncCLIENT_SECRETSlack OAuth 应用客户端密钥BASE_URL公共 Worker URL不含尾部斜杠本地开发默认http://localhost:8787/gatekeeper/slack本地开发时无需手动设置CLIENT_ID/CLIENT_SECRETrun-dev-server.ts 将根目录.dev.vars中的SLACK_CLIENT_ID/SLACK_CLIENT_SECRET映射为这两个变量这也是包内dev脚本提示在根目录运行pnpm dev-server的原因见 package.json。BASE_URL的解析逻辑见 slack.tsgetBaseUrl会去掉尾部斜杠getBasePath提取其路径段Worker 的fetch处理器会校验请求路径必须匹配该路径否则抛错拒绝。2.3 应用配置要点按 README 与源码Slack 应用必须正确配置三项Redirect URL必须与BASE_URL/oauth完全一致。本地开发默认即http://localhost:8787/gatekeeper/slack/oauth——注意 Worker 的 OAuth 回调处理器正是监听相对路径/oauth见 slack.ts并用getBaseUrl(env) /oauth作为redirect_uri传给 Slack。启用令牌轮换OAuth Permissions → Token Rotation启用后令牌短期有效约 12 小时通过oauth.v2.access?grant_typerefresh_token自动刷新未启用的传统长效令牌作为兜底按原样使用。轮换令牌是单次使用的这正是 UserAccount DO 用#credentialUpdate串行化刷新、重连与吊销操作的原因。申请所需 User Token Scopes按授权资源粒度申请见下节。users:read始终被请求用于已连接账户展示与用户名解析源码中即IDENTITY_SCOPES [users:read]见 slack.ts。2.4 令牌生命周期管理源码级令牌的存取与刷新全部收敛在UserAccountDurable ObjectSQLite 存储见 wrangler.jsonc中换取与暂存acceptAuthCode完成授权码交换后写入accessToken/refreshToken/grantedScopes/userId/teamId重连reconnect时新凭据先经stageCredentials暂存待 Workshop 确认浏览器持有者后才由commitReconnect提交生效期间绑定中的 Gadget 继续使用旧令牌见 slack.ts定时刷新getAccessToken在令牌过期前 5 分钟ACCESS_TOKEN_EXPIRY_SAFETY_MS触发刷新刷新失败invalid_refresh_token/token_expired/invalid_grant/token_revoked时回调credentialsExpired通知后端并要求用户重新认证见 slack-api.ts自动清理连接流程若从未完成setCallback会设置 1 小时闹钟alarm自毁revoke会同时吊销 access 与 refresh 令牌并清空存储见 slack.tsNonce 防重放32 字节加密随机 nonce 经历initiation → oauth两阶段每阶段 10 分钟过期用crypto.subtle.timingSafeEqual常量时间比较校验OAuth state 在换取前即被消费防止回调重放见 slack.ts。三、资源粒度与授权三种 URL 模式、三类会话访问按三种粒度授予每种可授权资源映射到一个 URL 模式同时驱动同意环节申请哪些 OAuth scope与路由环节把资源 URL 路由到哪个 gatekeeper 类粒度URL 模式会话类型整个工作区https://*全实例兜底SlackWorkspaceSession单个会话频道 / 私信 / 群组私信https://app.slack.com/client/:teamId/:conversationIdSlackConversation单个线程https://*.slack.com/archives/:conversationId/:messageIdSlackThread工作区授权复用框架的账户级https://*模式更具体的会话与线程 URL 优先。频道与私信共用同一种Conversation授权。源码中三种SupportedResource定义与SUPPORTED_RESOURCES列表见 slack.ts。3.1 各资源的用户令牌作用域资源申请的用户令牌作用域工作区team:read、会话读取类 scope、search:read会话会话读取类 scope、search:read线程channels:history、groups:history、im:history、mpim:history始终申请users:read其中会话读取类 scope指channels/groups/im/mpim各自的:read与:history即channels:read、channels:history、groups:read、groups:history、im:read、im:history、mpim:read、mpim:history八项源码常量CONVERSATION_READ_SCOPES见 slack.ts。作用域与资源的映射有完整的双向换算逻辑见 slack.tsresourceUrlPatternsToScopes把要授权的资源 URL 模式换算成 OAuth 请求的作用域集合users:read恒在grantedResourcesFromScopes授权回调返回的grantedScopes反向换算成已授予的资源——只有全部必需 scope 都授予时该资源才暴露避免部分授权造成的越权缝隙未知的资源 URL 模式会直接抛错拒绝validateResourceUrlPatterns。3.2 配置器 UI三种授权交互授权环节由三套配置器 UI 支撑源码在 configurator/工作区workspace-configurator-ui.tsx无需任何输入即就绪资源 URL 自动解析为https://app.slack.com/client/teamId会话conversation-configurator-ui.tsx提供自动补全下拉框可搜索频道 / 私信 / 群组私信后端 ConversationConfiguratorUI 分页拉取用户会话并本地过滤最多扫描 5 页、每页 200 条、返回上限 100 个选项线程thread-configurator-ui.tsx要求粘贴 Slack 消息链接https://workspace.slack.com/archives/C…/p…并校验主机名必须以.slack.com结尾、路径为/archives/:conversationId/:messageId且 ID 符合[CDG][A-Z0-9]与p[0-9]格式。四、会话 APIAgent 的只读能力面完整类型定义见 types.d.ts这是 Agent 面向的公开契约。三类会话的能力如下4.1SlackWorkspaceSession整个工作区方法说明getInfo()获取工作区元数据team ID、名称、域名listChannels()列出连接用户所在的公开与私有频道分页CursorlistDirectMessages()列出连接用户参与的私信与群组私信分页CursorlistUsers()列出工作区成员分页CursorgetUser(userId)按 Slack 用户 ID 查询单个用户getConversation(conversationId)获取指定会话频道或私信的能力对象无权限则抛错search(query)按 Slack 搜索语法跨工作区搜索消息如from:bob in:#engineering budget4.2SlackConversation单个会话方法说明getInfo()会话元数据类型、名称、话题、成员数等members()列出会话成员分页Cursor1:1 私信可能只返回连接用户本人识别对方请用getInfo().peerlistMessages()列出会话消息最新在前分页Cursor线程回复不混排需用getThread()getThread(threadTs)获取包含指定消息ts的线程能力根消息或任一回应的ts均可search(query)会话内搜索无论查询怎么写结果都硬性限制在本会话内任何in:限定词都无法扩大范围会话内搜索的安全边界值得强调实现上先把查询改写为in:#频道名 query作为搜索提示但真正的权威边界是服务端按restrictChannelId过滤结果——searchMessages会丢弃所有channel.id ! restrictChannelId的匹配见 slack-api.ts。README 所称硬限制hard-restricted即源于此。4.3SlackThread单个线程方法说明getRoot()获取线程根父消息listReplies()列出最多 1,000 条线程消息含根消息旧在前listReplies的实现限制为最多 20 页、每页 50 条MAX_REPLY_PAGES/HISTORY_PAGE_SIZE超出部分截断见 slack.ts。4.4 数据模型与分页约定列表 / 搜索方法返回前向分页的Cursor对象反复调用next()直到返回null使用完毕含提前结束需 dispose见 types.d.ts。SlackCursor内部串行化并发的next()调用且每一页在返回给调用方之前都会经过授权检查见 slack.ts条目类型做了能力捆绑SlackConversationEntry把会话元数据与可读该会话的能力对象打包SlackMessageEntry把消息与其线程能力打包取到即可直接深入无需二次查找见 types.d.ts已知提及mention会渲染为可读名称resolveText把user、#channel、!here、!subteam^…、链接与 HTML 实体统一解析为可读文本见 slack-api.ts作者与提及用户会批量预取并缓存消息时间戳ts是线程的 IDSlack permalink 中的p秒微秒编码可还原为tsmessageIdToTs见 slack.ts。五、底层原理路由、授权与协作防护5.1 从资源 URL 到 gatekeeper 类SlackUserImpl.getGatekeeperClassFor解析 URL 并路由见 slack.ts主机名以.slack.com结尾且路径为/archives/conversationId/messageId→SlackThreadGatekeeperImplthread_ts参数或消息 ID 解码确定线程根主机名为app.slack.com且路径为/client/teamId/conversationId→SlackConversationGatekeeperImpl其余app.slack.com/client/teamId→SlackWorkspaceGatekeeperImpl无法识别的 URL 直接抛Unsupported Slack resource URL。会话对象SlackWorkspaceSessionImpl等由各 gatekeeper 的startSession(approvalQueue)创建并持有 API 客户端、批准队列与工作区场景下观察者追踪器见 slack.ts。5.2 观察者Observer校验协作时如何防止越权Cloudflare OS 支持把已读取的数据分享给协作观察者。Slack gatekeeper 的观察者校验完全基于观察者自己的令牌由SlackVerifier回答两个问题见 slack.tsgetTeamId()观察者令牌所属工作区用于确认其是同一工作区成员hasConversationAccess(id)以观察者令牌调用conversations.info——公开频道对任何工作区成员可解析私有频道 / 私信 / 群组私信仅对成员 / 参与者可解析从而忠实执行 Slack 的 ACL会话 ID 全局唯一也顺带拒绝了跨工作区会话。校验策略因绑定粒度而异见 slack.ts会话 / 线程绑定采用ACL 检查单单元策略。绑定即单个会话线程继承其会话的 ACL只需在addObserver时用观察者自己的令牌确认其可读该会话之后读取的内容不可能超出该会话因此不追踪观察者removeObserver为空操作工作区绑定采用按会话的数据集追踪策略。一个工作区绑定跨越大量 ACL 各异的会话因此 gatekeeper 记录 Gadget 实际观察过哪些会话trackedConversation:…状态pending→observedaddObserver要求工作区成员身份 对所有已观察会话的访问权当首次观察新会话时#prepareConversationObservation会排除所有无权访问它的现有观察者且观察被批准队列拦截时该会话保持pending、不会记为已泄露。校验的最终布尔结果只回传给 Slack gatekeeper 自身因此可以信任。5.3 每次读取都经过批准队列所有暴露会话身份或内容的读取都经由authorizeConversationObservation走批准队列工作区绑定下它会先做数据集追踪再授权单单元绑定下则是普通授权见 slack.ts。例如listMessages每页都会提交Read a page of N messages from conversation 的描述供批准工作区级别的元数据读取成员目录等任何成员可见会话 ID 列表为空时直接授权。5.4 稳健的 API 客户端slack-api.ts 中的客户端包含工程细节限流重试对 429 响应最多重试 2 次按Retry-After头等待上限 30 秒RATE_LIMIT_MAX_RETRIES/RATE_LIMIT_MAX_WAIT_MS并发上限所有子请求扇出批量预取用户、批量校验观察者控制在 5 路并发以内低于 Workers 6 路并发请求上限MAX_CONCURRENT_REQUESTS见 slack.ts并采用逐批Promise.all、首个失败即整体失败的fail-closed语义错误映射SlackApiError把 Slack 错误码映射为可读消息并区分isAccessError令牌用户无权看到该资源如channel_not_found、not_in_channel、no_permission与isAuthError令牌过期或吊销如invalid_auth、token_expired——观察者校验正是靠这一区分把无法证明有权限保守判定为无权限见 slack-api.tspermalinks通过无需额外 scope 的auth.test获取工作区主机为消息补齐https://host/archives/…链接线程消息附带thread_ts与cid查询参数恰好匹配线程资源 URL 模式。5.5 搜索的页式游标适配Slack 的search.messages是基于页码而非游标的接口客户端把页码编码进游标字符串String(page 1)并根据paging.pages判断是否还有下一页见 slack-api.ts。六、构建与部署包内构建命令见 package.json# 构建含 capnweb RPC 校验代码生成 pnpm exec vp run -F gadgets/slack-gatekeeper build相关脚本说明dev包内不可直接启动须在仓库根目录运行pnpm dev-server由 run-dev-server.ts 统一拉起各 gatekeeper 并完成环境变量映射deploy先执行build:configurator再wrangler deploy部署前的类型校验由 wrangler.jsonc 的构建钩子完成pnpm exec capnweb-validate build --out .wrangler/validate见 wrangler.jsonc。运行时形态见 wrangler.jsoncWorker 需要 SQLite 持久化迁移声明了UserAccount、SlackWorkspaceGatekeeperImpl、SlackConversationGatekeeperImpl、SlackThreadGatekeeperImpl四个 Durable Object 类。部署时把CLIENT_ID/CLIENT_SECRET作为 wrangler secrets 注入它们刻意不写入 wrangler.jsonc。七、实践要点速查最小配置路径创建 Slack 应用 → 配置 Redirect URL 为BASE_URL/oauth→ 开启 Token Rotation → 按需勾选 User Token Scopes → 注入CLIENT_ID/CLIENT_SECRET→pnpm dev-server本地联调选择授权粒度需要频道 / 私信 / 搜索全览选工作区SlackWorkspaceSession只需单一频道或私信选会话SlackConversation只读一条讨论串选线程SlackThreadscope 最小、暴露面最小记住只读边界三类会话都无写入 / 操作能力getAutoApprovableActions恒为空任何 action 调用都会抛错分页与释放所有Cursor都要next()至null并 dispose线程回复上限 1,000 条搜索查询非空且 ≤ 1,000 UTF-8 字节会话内搜索不可逃逸SlackConversation.search无论查询写什么结果都由服务端按会话 ID 硬过滤。延伸阅读连接流程与页面gadgets/gatekeeper-kit 的 connect-pages / credential-stage观察者与授权框架契约workshop-shared 的 gatekeeper 模块GatekeeperUser、ApprovalQueue、Cursor等其他 gatekeeper 对照gatekeeper-google、gatekeeper-github、gatekeeper-confluence赞分享人工智能AI 应用AI AgentAgent 沙箱AI 安全治理【免费下载链接】cloudflare-osAgent workspace built on Cloudflare Workers for creating documents, building apps, and running agents with your company’s context and systems.项目地址https://gitcode.com/gh_mirrors/cl/cloudflare-os点击查看免费下载相关推荐Cloudflare OS Notion 门卫Notion Gatekeeper实战指南构建基于 Cloudflare Workers 的 Notion 页面与数据库访问代理Cloudflare OS Notion 门卫Notion Gatekeeper实战指南构建基于 Cloudflare Workers 的 Notion人工智能AI 应用AI AgentAgent 沙箱AI 安全治理基于 Cloudflare OS Gatekeeper 的 Supabase 集成指南OAuth2 连接、只读查询与人审 SQL 执行基于 Cloudflare OS Gatekeeper 的 Supabase 集成指南OAuth2 连接、只读查询与人审 SQL 执行 导读 本文围绕 Clo人工智能AI 应用AI AgentAgent 沙箱AI 安全治理WeKan 在 Ubuntu Touch 上的安装与更新机制解析OpenStore click 包与系统镜像 OTAWeKan 在 Ubuntu Touch 上的安装与更新机制解析OpenStore click 包与系统镜像 OTA Ubuntu TouchUBports人工智能AI 应用AI AgentAgent 沙箱AI 安全治理上一篇Navicat Mac版无限试用重置终极指南3种简单方法实现永久免费使用下一篇Klavis Google Slides MCP Server 实战指南基于 MCP 协议创建、编辑与管理演示文稿创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表