mcpField
R
restricted-access

restricted-access

github.com/val-town安全1041 次安装5 周前更新
代码仓库

关于 restricted-access

这是用于配置 Val Town val HTTP 端点受限访问的技能,说明组织授权、机器绕过令牌和访问者身份,并区分代码隐私与端点访问设置。

主要功能

  1. 01区分代码与端点隐私
  2. 02配置端点访问权限
  3. 03授予或撤销组织访问权
  4. 04管理自动化绕过令牌
  5. 05在服务端解析访问者身份

适用场景

  1. 01将内部工具限制为组织访问
  2. 02用绕过令牌允许 Webhook 请求
  3. 03排查受限端点的重定向
  4. 04识别已登录的人类访问者

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/val-town/plugins --skill restricted-access

安装后在 Claude Code 中输入/restricted-access确认已加载。

详细介绍

受限应用访问

一个 val 有两项相互独立的访问设置。更改其中一项不会影响另一项:

  • 代码(privacy:public / unlisted / private)——谁可以在 val.town 上查看源代码。
  • 应用访问(httpPrivacy:public / restricted)——谁可以调用 val 的 HTTP 端点。

一个 val 可以有私有代码,但端点完全开放;也可以代码公开,但端点受到限制。update_val 的 privacy 字段只会更改第一项;应用访问则通过 set_http_privacy 更改。

已启用此功能的组织可以使用受限应用访问。在此类组织中创建的 val 可能默认设为 restricted——请始终从 get_val_detail、list_vals、create_val 或 remix_val 的响应中读取 httpPrivacy,不要假设新 val 的 URL 是开放的。

这是不是合适的工具?

有两种不同的做法,听起来都像是“让我的应用要求登录”:

  • 受限应用访问(本技能)在平台边缘拦截端点,在你的代码运行前完成。没有访问权限的请求永远不会到达 val。你无需编写任何身份验证代码。访问权限授予整个组织,而非个人。
  • std/oauth(参见 oauth 技能)在你的 val 内部运行:你包装处理程序,任何拥有 Val Town 账户的人都可以登录。你可以控制会话,并构建面向每个用户的功能。

如果是只有团队成员才能访问的内部工具,请选择受限访问。如果任何 Val Town 用户都可以登录,且应用需要定义自己的登录用户概念,请选择 std/oauth。

不要误将两者叠加使用。在已受限的 val 中添加 oauthMiddleware,意味着访客要进行两次身份验证——先通过访问关卡,再在你的代码中验证。如果受限 val 需要知道谁在查看,请使用下方的身份标头,而不是添加 OAuth。

谁可以通过

访问权限授予组织,而非个人。只有当 val 已获准某个组织访问,且访客是该组织的成员时,访客才能进入。移除其中任一项授权,访问权限会在下一次请求时立即撤销——不会在会话期间缓存。

授权来源包括:

  • 直接授权——add_allowed_user 为组织授予访问权限,list_allowed_users 显示当前授权,remove_allowed_user 撤销授权。
  • 域名规则——val 可以允许所有使用指定域名电子邮件地址的人访问。这些规则会与直接授权一起显示在 list_allowed_users 中。
  • 邀请——可以通过电子邮件邀请获授权组织以外的人;对方接受邀请后即可访问。
  • 绕过令牌——供机器使用、限定于特定项目的密钥;见下文。

其他人会看到什么

未经身份验证的请求不会到达 val。平台会返回 302,将请求重定向到 Val Town 登录或授权页面。这是调试受限 val 时最常见的困惑来源:

  • fetch_val_endpoint 会报告重定向,但不会跟随它。
  • curl 显示的是指向 val.town 的 302,而不是你的响应。
  • API 客户端收到的是登录页面的 HTML,而不是预期的 JSON。
  • 无访问权限但已登录的访客会收到 403,说明他们需要访问其所在的组织。

这些都不意味着 val 的代码有问题。请先检查 httpPrivacy——如果它是 restricted,说明访问关卡正在正常工作。你可以通过 set_http_privacy 将 val 设为公开、授权调用方所在的组织,或使用绕过令牌。

自动化和 Webhook

机器无法完成登录重定向,因此接收 Webhook(Stripe、GitHub、另一个 val 中的定时任务)的受限 val 需要一个绕过令牌——其密钥仅限该 val 使用。

使用 create_bypass_token 创建令牌;密钥只会显示一次,之后无法再次获取。使用 list_bypass_tokens 管理令牌,使用 revoke_bypass_token 撤销令牌。

任选以下一种方式传递:

// Header (preferred — keeps the secret out of logs and referrers)
await fetch(url, { headers: { "X-Val-Town-Access": Deno.env.get("MY_BYPASS_TOKEN")! } });

// Query param (for services that only accept a URL, e.g. some webhook configs)
await fetch(`${url}?val_town_access=${Deno.env.get("MY_BYPASS_TOKEN")}`);

平台会在处理程序运行前移除标头和查询参数,因此你的代码不会看到它们。使用绕过令牌的请求不携带任何访客身份——它是匿名的机器调用者。

识别访问者

对于通过入口访问的用户,平台会转发一个短期有效的签名 X-Val-Town-User 标头。它本身并非用户身份信息——请使用 val 自己的 API 令牌,通过 Val Town 的 API 查询访问者的个人资料;Val Town 会将该令牌注入 valtown 环境变量:

const IDENTITY_HEADER = "X-Val-Town-User";

/** Returns the viewer's public profile, or null when there isn't one. */
async function getViewer(req: Request) {
  const signed = req.headers.get(IDENTITY_HEADER);
  if (!signed) return null;

  const res = await fetch("https://api.val.town/v3/val/viewer", {
    headers: {
      Authorization: `Bearer ${Deno.env.get("valtown")}`,
      [IDENTITY_HEADER]: signed,
    },
  });
  if (!res.ok) return null;

  // { id, username, type, bio, profileImageUrl, url, links }
  return await res.json();
}

需要注意的规则:

  • 始终将访问者视为可选项。 公开 val 或使用旁路令牌的请求都不会提供访问者。切勿使用 ! 断言其存在,也不要对空结果进行索引。
  • 每次请求都在服务端解析访问者身份。 凭据有效期很短,且与您的 val 绑定——不要持久化、传递给浏览器,也不要尝试在客户端代码中查询。
  • 返回的只有公开个人资料字段——用户名、简介、头像、个人资料 URL。不包括电子邮件地址和计费等级。不要构建依赖这些信息的 val。

上述传输方式(X-Val-Town-User 加上 /v3/val/viewer 查询)是目前的实现方式,之后可能会变;但这三条规则始终适用。

管理应用访问权限

任务工具
检查当前设置get_val_detail(httpPrivacy 字段)
将端点设为公开或受限set_http_privacy
查看有权访问的用户list_allowed_users
授予 / 撤销组织权限add_allowed_user / remove_allowed_user
创建 / 列出 / 撤销自动化密钥create_bypass_token / list_bypass_tokens / revoke_bypass_token

受限 val 只能由 val.town 在 iframe 中嵌入,因此无论登录用户是谁,将其嵌入外部网站都会被浏览器拦截。

评论

支持 Markdown