---
type: tutorial
title: 从应用市场添加一个游戏
summary: 浏览应用市场，在你的站点密钥上安装一个游戏、把它设为必需，然后换掉一个元素，让访客去通过一个真正可玩的游戏挑战。
---

BananaSeed 的联系表单已经有了一个能用的组件，来自 [上一节课](/docs/getting-started/add-the-widget)。在这最后一节课里，我们把朴素的复选框换成一个真正可玩、每位访客都必须通过的游戏。

复选框既然已经能用，何必费这个事？复选框是不动声色的下限。游戏把那个躲不掉的“证明你是真人”的时刻，从一桩让访客忍受的事，变成一桩让他享受的事，而且它正是能扛住老练攻击者的那一部分。今天的 AI 能勾选复选框、能解图片网格，但一个真正的游戏是它作不了弊的那一道挑战，因为没有机器会像真人那样去玩。💪

这节课比放进组件要稍微费点功夫：你挑一个游戏，把它安装到你的站点密钥上，再打开那个要求它的关卡。回报是，游戏成了真正挡在机器人和你的表单之间的那个东西，而不是你能一掠而过的装饰。底下的令牌机制完全一样，所以你的后端一点都不用改。这里的一切都能在免费套餐上用。

## 你在结束时会拥有什么

- 一个来自应用市场的游戏，已安装在你的站点密钥上。
- 该游戏被设为验证必需，于是一个光秃秃的复选框再也无法通过。
- 同一个联系表单，现在由游戏守护，而你的后端检查丝毫未变。

## 1. 从应用市场挑一个游戏

[应用市场](/marketplace) 是你从中选择的公开目录。打开它浏览：按类别筛选，或按一个游戏支持什么来筛选（触屏、键盘、屏幕阅读器、声音），这样你就能把游戏匹配到你的受众。每个游戏都有自己的页面，带预览和一个像 `caputchin/games/leaf-memory` 这样的 id。

浏览是开放的，没有审批队列：目录里的每个游戏都可直接使用。挑一个，复制它的 id。本节课余下的部分我们会用 **Leaf Memory**（`caputchin/games/leaf-memory`）。

## 2. 在你的站点密钥上安装游戏

在一个游戏能守护某个密钥之前，你要把它安装到那个密钥上。安装是在告诉 Caputchin 给这个游戏拍一份固定、已核验的快照，于是你访客所玩的那个确切版本，就是 Caputchin 日后核验结果时能重新跑一遍的那个版本。

在仪表盘里，打开你的团队，打开你的站点密钥，前往它的 **游戏** 页。在 **添加游戏** 面板里，在 **应用市场游戏** 框中搜索那个游戏，并从列表里选中它（或点击 **打开**）。

Caputchin 会注册这个游戏，给它拍下快照，再把你放到游戏的设置页上。这个游戏现在会出现在游戏页上的 **已注册游戏** 下面，准备好守护该密钥了。几乎每个应用市场游戏一经注册就准备就绪，第一方游戏则永远如此；如果某个少见的游戏在这里显示 **不可回放** 徽章，那么在作者交付一个可回放的构建之前，它都无法设关卡。

你可以添加不止一个游戏。把它们添加到单个站点密钥上，或者在团队上添加一次，让同一组游戏在团队里的每个密钥间共享。

<Callout type="success">你的站点密钥现在装好了一个游戏，并已核验。接下来我们把它设为必需。🎉</Callout>

## 3. 要求一个游戏来验证

安装一个游戏让它可用；它还没有强迫任何人去玩它。关卡才做这件事。

在你的站点密钥上，打开它的 **安全** 页，并打开 **要求一个游戏来验证**。从此往后，这个密钥的每位访客都必须玩它已安装游戏中的一个才能通过，而通过一个光秃秃的复选框已经不够了。（在至少安装一个游戏之前，你打不开这个关卡，这正是第 2 步排在前面的原因。）

关卡一开，Caputchin 就会为每位访客选定他拿到哪个已安装游戏，并通过一张一次性的、签名的票据发给他。访客也好，机器人也罢，都无法挑选游戏、跳过它、或把它换成一个更容易的：这个选择是在 Caputchin 这一侧做出的，每个会话都重新来过。正是这一点，把游戏从一件锦上添花的事变成了真正的防护。

在管理一整组密钥？团队有自己的 **安全** 页，带 **在每个站点密钥上要求一个游戏**，它会一次性在团队里的每个密钥上打开这个关卡。

## 4. 换掉元素

现在到页面。游戏在一个不同的元素 `<caputchin-game>` 上渲染。你已经加好的 `import "@caputchin/widget"` 也会注册它，所以没有什么新东西要装。因为密钥现在要求一个游戏，只有复选框的 `<caputchin-widget>` 再也无法在它上面通过，所以这次替换是最后一个必需步骤。

在你的联系表单里，改这一行：

```jsx
// before
<caputchin-widget sitekey="cpt_pub_..." />

// after
<caputchin-game sitekey="cpt_pub_..." />
```

你不用传一个游戏 id。因为密钥要求一个游戏，Caputchin 会送上你已安装游戏中的一个，并逐次访问地挑选它。如果你宁愿固定某一个，或者把轮换限制到一个子集，就把它们点名（每一个都必须安装在该密钥上）：

```jsx
// always Leaf Memory
<caputchin-game sitekey="cpt_pub_..." game="caputchin/games/leaf-memory" />

// a random one of these two per visit
<caputchin-game
  sitekey="cpt_pub_..."
  games="caputchin/games/leaf-memory,caputchin/games/dino-runner"
/>
```

点名一个没安装在该密钥上的游戏不会加载它：组件会报告关卡里没有这样的游戏，而不会放访客通过。

想控制游戏在你页面里如何摆放（一个 inline 面板、一个 modal，还是 fullscreen）以及它渲染多大，见 [尺寸与布局](/docs/references/widget-sizing)。

## 5. 试一试

重载你的应用。复选框不见了：访客现在在一个沙箱化的 iframe 里玩游戏。当他赢了，组件会往表单里加上同一个隐藏的 `caputchin-token` 字段，于是你的 `FormData` 读取和你后端的 `/siteverify` 检查，相比上一节课都丝毫未变。

打开你站点密钥的统计页，你会看到会话流经和之前一样的那条漏斗。你可以把整个视图筛选到单个游戏，以便把一个和另一个相比较。

<Callout type="success">BananaSeed 的联系表单现在由一个真正可玩、每位访客都必须通过的游戏守护，而每一次提交仍在你的服务器上被核验。你把它交付了。🎉</Callout>

你从一个空账户，走到了一个已核验、由游戏守护的表单。

## 刚刚发生了什么

| 步骤 | 在哪里 | 结果 |
|---|---|---|
| 挑一个游戏 | 应用市场 | 你有了一个像 `caputchin/games/leaf-memory` 这样的游戏 id。 |
| 把它安装到密钥上 | 仪表盘，密钥的游戏页 | Caputchin 固定一份已核验的快照；游戏出现在已注册游戏下，准备好设关卡（第一方游戏立即就绪）。 |
| 要求一个游戏 | 仪表盘，密钥的安全页 | 每位访客都必须通过一个已安装游戏，而由 Caputchin 挑选哪一个。 |
| 换成 `<caputchin-game>` | 你的页面 | 游戏在一个沙箱化的 iframe 里加载，并加上同一个 `caputchin-token`，所以你的后端未变。 |

## 接下来是什么

这些是你从这里出发最可能会用到的领域：

- [自定义游戏](/docs/game-customization/overview)：设置你游戏的语言、皮肤和难度。
- [安全](/docs/site-keys/security)：游戏关卡、proof-of-work 难度、来源，以及一个密钥的其余防护。
- [统计与会话](/docs/site-keys/statistics)：读懂漏斗，把一个游戏和另一个相比较。
- [账户管理](/docs/account-management/overview)：登录、访问令牌、账单和席位。
- [团队](/docs/troops/overview)：组织你的站点密钥，并在付费套餐上邀请你的团队。
