

# 生成并签名 IVS 播放令牌
<a name="private-channels-generate-tokens"></a>

有关使用 JWT 和受支持的库签名令牌的详细信息，请访问 [jwt.io](https://jwt.io/)。在 jwt.io 界面上，您必须输入私有密钥才能签署令牌。只有当您想验证令牌时才需要公有密钥。

## 令牌架构
<a name="private-channels-tokens-schema"></a>

所有 JWT 都有三个字段：标头、有效负载和签名。
+ **标头**指定了如下内容：
  + `alg` 是签名算法。这是 ES384，是一种使用 SHA-384 哈希算法的 ECDSA 签名算法。
  + `typ` 是令牌类型（即 JWT）。

  ```
  {
    "alg": "ES384",
    "typ": "JWT"
  }
  ```
+ **有效负载**包含特定于 Amazon IVS 的数据：
  + `channel-arn` 是视频播放请求的参考。
  + `access-control-allow-origin` 是一个可选字段，可用于将播放限制到指定[源](https://developer.mozilla.org/en-US/docs/Glossary/Origin)；即设置为仅可从指定网站查看视频流。例如，您可能想要阻止用户将播放器嵌入到其他网站上。预设情况下，允许在所有源中播放。（请注意，这仅限制浏览器客户端；不会限制来自非浏览器客户端的播放。） 此字段可以包含多个源，以逗号分隔。允许使用通配符域名：每个源的主机名都可以用 \* 开头（例如：https://\*.amazon.com）。如果 `strict-origin-enforcement` 为 `true`，则最多可以指定 5 个域；否则，没有最大值。
  + `strict-origin-enforcement` 是一个可选字段，可用于加强 `access-control-allow-origin` 字段中指定的源限制。默认情况下，`access-control-allow-origin` 限制仅适用于多变体播放列表。如果启用 `strict-origin-enforcement`，服务器将强制要求请求源与所有播放请求（包括多变体播放列表、变体播放列表和片段）的令牌匹配。这意味着所有客户端（包括非浏览器客户端）都必须在每个请求中提供有效的源请求标头。使用 `setOrigin` 方法在 IVS iOS 和 Android 回放器 SDK 中设置标头。除 iOS Safari 之外，它会在 Web 浏览器中自动设置。对于 iOS Safari，您需要将 `crossorigin="anonymous"` 添加到视频元素，以确保发送源请求标头。示例：`<video crossorigin="anonymous"></video>`。
  + `single-use-uuid` 是可选字段，其中包含您在创作令牌时生成的有效的[通用唯一标识符（UUID）](https://en.wikipedia.org/wiki/Universally_unique_identifier)。如果添加此字段和 UUID 值，则生成的关联令牌在用于获取多变体播放列表和观看流后将失效。一次性身份验证令牌让恶意用户更难在您的私有通道上与其他观众分享流式传输。请注意，使用 `single-use-uuid` 申请时，`exp` 申请的最大值为未来 10 分钟。
  + `viewer-id` 是一个可选字段，其中包含一个用于跟踪和引用授予令牌的查看者的 ID。此字段是必填字段，以便将来能够撤消查看者的查看会话。最大长度为 40 个字符，并且该值必须符合字符串的条件。请勿将此字段用于个人识别信息、机密信息或敏感信息。请注意，使用 `viewer-id` 时，`exp` 的最大值为未来 10 分钟。
  + `viewer-session-version` 是一个可选字段，其中包含与此查看者会话关联的版本。当撤消查看者会话时，此值可用于筛选已撤消的查看者会话。例如，在此处指定 Unix 时间戳将允许撤消在指定时间之前启动的所有会话。该值必须是一个 64 位有符号整数 (Int64)。该字段应与 `viewer-id` 一起提供（可选）；它本身不起任何作用。默认值是 0。
  + 借助 `maximum-resolution`，可以根据观看者权限，为观看者会话指定按分辨率进行清单筛选。例如，将此字段设置为 `HD` 意味着观看者将获得小于或等于 `HD` 的分辨率。
  + `ads-opt-out` 是可选字段，使您可以选择不让某个观众接收广告。允许的值包括 `true` 和 `fals`。排除此字段时的默认值为 `false`。有关更多信息，请参阅[服务器端广告插入](https://docs.aws.amazon.com/ivs/latest/LowLatencyUserGuide/server-side-ad-insertion.html)。
  + `ads-player-params` 是可选字段，使您可以将参数传递给 Elemental MediaTailor，就好像这些参数是播放器参数一样。您放入此列表中的键始终以命名空间形式作为 `player_params` 模板参数处理。所有键和值的总有效载荷大小限制为 1000 字节。
  + `exp` 是令牌到期时的 Unix UTC 时间戳。这并不代表视频流可以查看的时长。在观众初始化播放时验证令牌，而不是在整个视频流中。将该值作为整数类型值输入。

    请注意，Unix 时间戳是一个数值，表示从 1970-01-01T00:00:00Z UTC 到指定 UTC 日期/时间的秒数（忽略闰秒）。不同的语言以不同的单位衡量 Unix 时间戳；例如，JavaScript 的 `Date.now()` 所返回的时间以毫秒为单位。（请参阅 [JWT RFC 部分 4.1.4](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.4) 中的 `exp`。）

  ```
  {
      "aws:channel-arn": "<channel_arn>",
      "aws:access-control-allow-origin": "<your-origin>",
      "aws:strict-origin-enforcement": true,
      "aws:single-use-uuid": "<UUID>",
      "aws:viewer-id": "<viewer_id>",
      "aws:viewer-session-version": "<viewer_session_version>",
      "aws:maximum-resolution": "SD" | "HD" | "FULL_HD",
      "exp": <unix timestamp>
  }
  ```
+ 要创建**签名**，可搭配使用私有密钥和标头 (ES384) 中指定的算法，对已编码的标头和已编码的负载进行签名。

  ```
  ECDSASHA384(
    base64UrlEncode(header) + "." +
    base64UrlEncode(payload),
    <private-key>
  )
  ```

## 说明
<a name="private-channels-tokens-instructions"></a>

1. 使用 ES384 签名算法以及与其中一个播放密钥资源关联的私有密钥生成令牌签名（请参阅上面的 `ECDSASHA384` 示例）。

1. 汇编令牌。

   ```
   base64UrlEncode(header) + "." +
   base64UrlEncode(payload) + "." +
   base64UrlEncode(signature)
   ```

1. 将签名令牌作为查询参数附加到播放 URL。

   ```
   https://b37c565f6d790a14a0e78afaa6808a80.us-west-2.playback.live-video.net/
   api/video/v1/aws.ivs.us-west-2.123456789.
   channel.fbc789c1-2c56-4ce6-a30a-d99275dc4481.m3u8?token=<token>
   ```

## Node.js 示例
<a name="private-channels-tokens-nodejs-example"></a>

以下方法就使用了 Node.js 在后端（通过微服务或无服务器应用程序）生成令牌。

```
import jwt from "jsonwebtoken";

const getToken = () => {
  const privateChannelArn = process.env.DEMO_PRIVATE_CHANNEL_ARN; // private channel ARN
  const privateChannelPrivateKey = process.env.DEMO_PRIVATE_CHANNEL_PRIVATE_KEY; // playback private key

  const payload = {
    "aws:channel-arn": privateChannelArn,
    "aws:access-control-allow-origin": "*",
    "exp": Date.now() + (60 * 1000), // expires in 1 minute
  };

  const token = jwt.sign(payload, privateChannelPrivateKey, { algorithm: 'ES384' });
  return token;
}
```

在前端应用程序中，可以检索此令牌并将其附加到私有频道的播放 URL，如下所示。

```
const streamUrl = `https://b37c565f6d790a14a0e78afaa6808a80.us-west-2.playback.live-video.net/api/video/v1/aws.ivs.us-west-2.123456789.channel.fbc789c1-2c56-4ce6-a30a-d99275dc4481.m3u8?token.m3u8?token=${token}`
const ivsPlayer = IVSPlayer.create();
ivsPlayer.attachHTMLVideoElement(document.getElementById('video-player'));
ivsPlayer.load(streamUrl);
ivsPlayer.play();
```