自定义年龄门控
本指南将引导您使用 k-ID API 直接实现自定义年龄门控,无需使用预构建的小部件。这种方法让您完全控制用户界面,同时 k-ID 处理合规逻辑。
本指南演示了一种简化的集成模式,其中所有权限在 Compliance Studio 中配置为基本权限。通过此配置,一旦创建会话(直接创建或在家长同意后创建),所有功能立即可用——无需会话升级流程。
什么是自定义年龄门控?
自定义年龄门控是您构建和控制的年龄验证界面,而 k-ID 的 API 在后台处理合规逻辑。这种方法适用于以下情况:
- 完全 UI 控制:设计符合您品牌和用户体验的年龄门控
- 平台集成:为移动应用或游戏引擎构建原生体验
- 自定义工作流程:将年龄验证作为更大入门流程的一部分实施
先决条件
开始之前,您需要:
- k-ID 产品:在 k-ID Compliance Studio 中创建和配置您的产品
- 基本权限配置:在产品的权限设置中将所有权限配置为"基本"
- API 密钥:从 Compliance Studio 中产品的开发者设置页面生成您的 API 密钥
- Webhook 端点(推荐):设置安全的 HTTPS 端点以接收挑战和会话事件。更多详情请参阅 Webhooks。
步骤 1:获取年龄门控要求
在显示年龄门控之前,调用 /age-gate/get-requirements 以根据用户的司法管辖区确定需要显示的内容。
在您的实现中,所有 API 调用都应该是服务器到服务器的,以保护您的 API 密钥不被暴露在客户端代码中。
请求示例
GET /api/v1/age-gate/get-requirements?jurisdiction=US-CA
Authorization: Bearer your-api-key
响应示例
{
"shouldDisplay": true,
"ageAssuranceRequired": false,
"digitalConsentAge": 13,
"civilAge": 18,
"minimumAge": 0,
"approvedAgeCollectionMethods": [
"date-of-birth",
"age-slider",
"platform-account"
]
}
响应字段
| 字段 | 描述 |
|---|---|
shouldDisplay | 是否应显示年龄门控 |
ageAssuranceRequired | 此司法管辖区是否需要年龄验证 |
digitalConsentAge | 数字同意的最低年龄(低于此年龄的用户需要家长同意) |
civilAge | 用户被视为法定成年人的年龄 |
minimumAge | 访问您产品的最低年龄(在 Compliance Studio 中配置) |
approvedAgeCollectionMethods | 此司法管辖区允许的年龄收集方法 |
如果 shouldDisplay 为 false,则跳过年龄门控并调用 /age-gate/get-default-permissions 获取该司法管辖区的默认会话权限。
步骤 2:构建您的年龄门控 UI
根据响应,使用批准的收集方法构建您的年龄门控界面:
date-of-birth:完整出生日期输入(YYYY-MM-DD)age-slider:年龄范围或滑块选择platform-account:使用现有平台账户年龄数据
有关年龄滑块行为、日期选择器要求和无障碍访问考虑事项的详细设计建议,请参阅 UX 指南。
年龄门控 UI 示例
<div id="age-gate">
<h2>请输入您的出生日期</h2>
<form id="age-gate-form">
<label for="dob">出生日期</label>
<input type="date" id="dob" name="dob" required />
<button type="submit">继续</button>
</form>
</div>
步骤 3:使用 API 检查年龄
当用户提交年龄时,使用收集的年龄信息和司法管辖区调用 /age-gate/check。根据您使用的年龄收集方法,可以传递 dateOfBirth 或 age。
使用出生日期的请求示例
如果您使用日期选择器收集完整的出生日期:
POST /api/v1/age-gate/check
Content-Type: application/json
Authorization: Bearer your-api-key
{
"jurisdiction": "US-CA",
"dateOfBirth": "2015-04-15"
}
使用年龄的请求示例
如果您使用年龄滑块收集用户的年龄:
POST /api/v1/age-gate/check
Content-Type: application/json
Authorization: Bearer your-api-key
{
"jurisdiction": "US-CA",
"age": 9
}
可能的响应
API 返回三种状态之一:
PASS: 用户可以继续
用户的年龄允许立即访问。创建具有所有权限的会话。
{
"status": "PASS",
"session": {
"sessionId": "608616da-4fd2-4742-82bf-ec1d4ffd8187",
"ageStatus": "LEGAL_ADULT",
"dateOfBirth": "2005-04-15",
"jurisdiction": "US-CA",
"permissions": [...],
"status": "ACTIVE"
}
}
操作:存储 sessionId 并允许用户继续。
PROHIBITED: 用户被阻止
用户的年龄低于为您的产品配置的最低年龄。
{
"status": "PROHIBITED"
}
操作:显示适合年龄的消息并阻止访问。
CHALLENGE: 需要家长同意
用户的年龄需要可验证的家长同意(VPC)。创建挑战供受信任的成人批准。
{
"status": "CHALLENGE",
"challenge": {
"challengeId": "683409f1-2930-4132-89ad-827462eed9af",
"oneTimePassword": "PP5BUS",
"type": "CHALLENGE_PARENTAL_CONSENT",
"url": "https://family.k-id.com/authorize?otp=PP5BUS"
}
}
操作:存储 challengeId 并显示受信任成人挑战屏幕(参见步骤 4)。
步骤 4:构建受信任成人挑战屏幕
当您收到 CHALLENGE 响应时,显示一个屏幕,允许用户联系受信任的成人以获取同意。挑战响应提供了您所需的一切。
有关监护人同意流程的详细设计建议,包括布局示例和实现技巧,请参阅 UX 指南中的监护人同意。
挑战屏幕选项
您的挑战屏幕应为受信任的成人提供三个选项来完成同意:
选项 1:电子邮件通知
允许用户输入受信任成人的电子邮件地址。提交后,调用 /challenge/send-email 发送同意请求电子邮件。
POST /api/v1/challenge/send-email
Content-Type: application/json
Authorization: Bearer your-api-key
{
"challengeId": "683409f1-2930-4132-89ad-827462eed9af",
"email": "parent@example.com"
}
选项 2:二维码
显示从 challenge.url 字段生成的二维码。受信任的成人可以用手机扫描此二维码直接访问同意门户。
// 从挑战 URL 生成二维码
const qrCodeUrl = challenge.url;
// 使用二维码库渲染: "https://family.k-id.com/authorize?otp=PP5BUS"
选项 3:手动输入代码
显示 challenge.oneTimePassword 并指示受信任的成人访问 asktoplay.com 并输入代码。
挑战屏幕实现示例
<div id="challenge-screen">
<h2>请让受信任的成人帮助您</h2>
<p>请让受信任的成人使用以下方法之一完成设置。</p>
<div class="options-container">
<!-- 选项 1:电子邮件 -->
<div class="option">
<h3>选项 1</h3>
<p>输入受信任成人的电子邮件</p>
<form id="email-form">
<label for="email">电子邮件</label>
<input type="email" id="email" placeholder="电子邮件地址" required />
<button type="submit">提交</button>
</form>
</div>
<!-- 选项 2:二维码 -->
<div class="option">
<h3>选项 2</h3>
<p>请让受信任的成人扫描或点击二维码。</p>
<div id="qr-code">
<!-- 从 challenge.url 渲染二维码 -->
</div>
</div>
<!-- 选项 3:手动代码 -->
<div class="option">
<h3>选项 3</h3>
<p>
前往 <a href="https://asktoplay.com">asktoplay.com</a> 并输入以下代码。
</p>
<div class="code-display">
<span id="otp-code">PP5BUS</span>
<button onclick="copyCode()">复制</button>
</div>
</div>
</div>
<button id="do-later">稍后再做</button>
</div>
存储挑战
在等待同意期间,存储 challengeId。您可以将其存储在本地存储、与用户账户关联的数据库或适合您平台的任何其他持久存储中。如果用户在同意授予之前返回您的应用,请使用 /challenge/get 检索挑战以恢复挑战屏幕。
// 创建挑战时存储(使用 localStorage 的示例)
localStorage.setItem("pendingChallenge", challengeId);
// 应用重启时,检查待处理的挑战
const pendingChallenge = localStorage.getItem("pendingChallenge");
if (pendingChallenge) {
// 获取挑战详情并显示挑战屏幕
const challenge = await fetchChallenge(pendingChallenge);
showChallengeScreen(challenge);
}
步骤 5:处理 Webhook 事件
配置您的 webhook 端点以在挑战状态更改或会话被删除时接收事件。
Challenge.StateChange 事件
当受信任的成人批准或拒绝同意请求时,会触发此事件。
{
"eventType": "Challenge.StateChange",
"data": {
"id": "683409f1-2930-4132-89ad-827462eed9af",
"productId": 42,
"status": "PASS",
"dob": "2015-04-15",
"sessionId": "0ad1641f-c154-4c2-8bb2-74dbd0de7723",
"approverEmail": "parent@example.com",
"kuid": "7a1f2c3d-4e5f-6789-abcd-ef0123456789"
}
}
| 状态 | 描述 | 操作 |
|---|---|---|
PASS | 同意已授予 | 存储 sessionId 并允许访问 |
FAIL | 同意被拒绝 | 显示适当消息,用户无法继续 |
IN_PROGRESS | 挑战仍在等待中 | 继续等待 |
处理成功的同意
当您收到 PASS 状态时(通过 webhook 或轮询),响应中包含 sessionId。您应该:
- 获取会话权限:使用
sessionId调用/session/get以获取包含权限的完整会话详情。
GET /api/v1/session/get?id=0ad1641f-c154-4c2-8bb2-74dbd0de7723
Authorization: Bearer your-api-key
响应示例:
{
"session": {
"ageStatus": "DIGITAL_MINOR",
"dateOfBirth": "2015-04-15",
"etag": "6d9d24fccd428f845b355122799948dd0a52fc5d",
"jurisdiction": "US-CA",
"kuid": "7a1f2c3d-4e5f-6789-abcd-ef0123456789",
"permissions": [
{
"enabled": true,
"managedBy": "GUARDIAN",
"name": "text-chat-private"
},
{
"enabled": false,
"managedBy": "GUARDIAN",
"name": "voice-chat"
}
],
"sessionId": "0ad1641f-c154-4c2-8bb2-74dbd0de7723",
"status": "ACTIVE"
},
"status": "PASS"
}
- 将存储的挑战替换为会话:清除
challengeId,改为存储sessionId。这表示用户现在拥有一个已授予权限的活跃会话。
// 清除待处理的挑战并存储活跃会话
user.challengeId = null;
user.sessionId = data.sessionId;
- 应用权限:使用会话响应中的权限在您的应用程序中启用或禁用功能。
Session.Delete 事件
当会话被删除时(例如,家长通过 Family Connect 撤销访问权限时),会触发此事件。
{
"eventType": "Session.Delete",
"data": {
"id": "0ad1641f-c154-4c2-8bb2-74dbd0de7723",
"productId": 42
}
}
操作:删除存储的会话并要求用户再次完成年龄门控流程。
Webhook 处理程序示例
app.post("/webhook/k-id", (req, res) => {
const { eventType, data } = req.body;
switch (eventType) {
case "Challenge.StateChange":
if (data.status === "PASS") {
// 授予访问权限 - 为用户存储 sessionId
grantAccess(data.sessionId, data.kuid);
} else if (data.status === "FAIL") {
// 拒绝访问
denyAccess(data.id);
}
break;
case "Session.Delete":
// 撤销访问权限 - 用户必须再次完成年龄门控
revokeSession(data.id);
break;
}
res.status(200).send("OK");
});
轮询作为备用方案
如果 webhook 不可用,您可以轮询 /challenge/get-status 来检查挑战状态:
GET /api/v1/challenge/get-status?id=683409f1-2930-4132-89ad-827462eed9af
Authorization: Bearer your-api-key
轮询时,请求之间至少等待 5 秒。如果轮询过于频繁,API 可能返回 HTTP 429。
Webhook 配置
对于自定义年龄门控流程,请确保您的 webhook 端点配置为接收:
Challenge.StateChange:家长同意被批准或拒绝时通知Session.Delete:家长删除会话时通知
有关验证 webhook 签名的信息,请参阅 Webhooks。
下一步
现在您已经实现了自定义年龄门控,请探索这些资源以增强您的集成:
- UX 指南:年龄滑块、日期选择器和同意流程的设计建议
- API 参考文档:年龄门控和挑战 API 的详细文档
- Webhooks 设置:为生产系统实现稳健的 webhook 处理
- 最佳实践:实施最佳实践以确保安全性和可靠的用户体验
- 测试:使用测试模式 API 测试您的集成
- 预发布检查清单:上线前查看要求
通过 k-ID 的自定义年龄门控集成,您可以构建完全品牌化的合规体验,同时 k-ID 处理复杂的司法管辖区逻辑和家长同意流程。