guide令牌端点

# 令牌端点概述

要将 CKEditor 5CKEditor 4 与 CKEditor 云服务连接,您需要创建自己的令牌端点。本指南将解释创建令牌端点所需了解的一些原理。

# CKEditor 云服务如何使用令牌

为了对用户进行身份验证,CKEditor 云服务使用令牌。令牌的目的是通知云服务用户有权访问资源,以及用户应该连接到哪个环境。令牌的真实性由数字签名提供。

令牌端点是使用 CKEditor 的客户端发出获取令牌请求的地方。只有在用户证明其身份的情况下,它才应返回令牌。

令牌端点应放置在您的系统内部。

Token endpoint diagram.

# JSON Web 令牌规范

CKEditor 云服务令牌表示为 JSON Web 令牌 (JWT)。JWT 是一种开放的 标准,用于传输数字签名的信息。使用它可确保数据来自受信任的来源。

令牌由三部分组成

  • 标头
  • 有效负载
  • 签名

每部分都使用 base64url 编码,并用点号分隔

header.payload.signature

示例令牌可能如下所示

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiSm9obiJ9.3MOd-0xmppWAX_86vMPjQ0PTKAniCtr762UTM5WuGa8

标头指示它是 JWT,并定义用于计算签名的哈希算法。它只是一个包含 typalg 属性的 JSON 对象,其中 typ 始终包含 JWT 值,而 alg 包含所用算法的名称。

# 有效负载

有效负载是一个包含声明的 JSON 对象。在 CKEditor 云服务中,它主要用于指定环境、用户数据和权限。

JWT 标准指定了一些预定义的声明,例如 aud(受众)、exp(过期时间)、sub(主体)或 iat(签发时间)。在 CKEditor 云服务中,我们使用 aud 来识别环境,使用 iat 来检查令牌是否已过期,以及使用 sub 来识别用户。

# 签名

与标头和有效负载不同,签名不是 JSON 对象,而是由加密算法生成的原始字节。

签名是针对合并的标头和有效负载计算得出的。它可以对数据进行身份验证,并验证令牌是否已被篡改。

signature = HMACSHA256(
    base64UrlEncode(header) + "." + base64UrlEncode(payload),
    secret
)

CKEditor 云服务支持由 HS256HS384HS512 算法创建的签名。

切勿泄露密钥,因为这将允许伪造令牌。

# 令牌

CKEditor 云服务的令牌应将 环境 ID 指定为 aud 属性,并且需要使用 访问密钥 进行签名。两者都可以在 CKEditor 生态系统客户仪表板(用于 SaaS)或管理面板(用于本地部署)中找到 - 请参阅 环境管理文档。可选地,令牌可以包含用户数据。否则,CKEditor 云服务将把用户视为匿名用户。

# 用户

如果用户不是匿名的,则有效负载应包含 sub 声明,该声明标识用户。您还可以放置一个 user 对象来定义其他属性,如 nameemailavatar。在匿名用户的情况下,将生成随机用户 ID。

用户标识符应在环境范围内是唯一的,因此您不应在两个应用程序中使用相同的 环境 ID,因为这会导致用户 ID 冲突。

# 计费

在使用 CKEditor 云服务的 SaaS 版本时,您将为每个唯一用户付费。使用 CKEditor 协作服务器的本地部署版本的客户受已连接的唯一用户的数量限制。

基于来自令牌的 aud(环境 ID)和 sub(用户 ID)属性的唯一对,对唯一用户进行计数。在匿名用户的情况下,每个用户都将单独计费,因为将分配随机用户 ID。

为了限制计费,请确保对每个真实用户,始终使用相同的唯一 sub(用户 ID)来生成令牌。为了测试令牌端点,我们建议创建一个恒定的示例用户有限列表。这将有助于您避免不必要的付款。在开发应用程序期间,您可以使用具有 10 个免费用户的免费、有限的 开发令牌端点

# 令牌有效负载

# 有效负载属性

以下属性必须包含在有效负载中

  • aud – 环境 ID。
  • iat – “签发时间”。确保 iat 存在并包含以秒为单位的正确时间。某些 JWT 实现默认情况下不包含它。有时系统时间也可能无效,导致令牌出现奇怪问题(例如,Docker for Mac 时间漂移)。
  • auth – 如果您打算使用协作功能,则需要其中的 auth.collaboration 角色。如果您只使用轻松图片或导出到 Word/PDF,则可以跳过此选项。

可选属性

  • sub – 用户 ID。
  • user – 用户信息。建议提供 nameemail
  • exp – 令牌过期时间。标识 JWT 不再被接受的过期时间。云服务只接受不早于 24 小时的令牌。此字段可用于缩短令牌有效期。

# 角色和权限

要定义对资源的权限,令牌有效负载应包含具有指定用户角色和/或权限的 auth 对象。

{
    "auth": {
        "collaboration": {
            "doc-1": {
                "role": "writer"
            },
            "doc-2": {
                "role": "commentator",
                "permissions": [
                    "comment:admin"
                ]
            },
            "doc-3": {
                "permissions": [
                    "document:read",
                    "document:write",
                    "comment:read"
                ]
            }
        }
    }
}

有关角色的更多信息,请参阅 角色指南

# 示例令牌有效负载

以下示例展示了一个完整的令牌有效负载,它允许访问环境中的所有文档进行编辑

{
    "aud": "NQoFK1NLVelFWOBQtQ8A",
    "iat": 1511963669,
    "sub": "exampleuser",
    "user": {
        "email": "example@cksource.com",
        "name": "A User",
        "avatar": "http://example.com/avatars/john.png"
    },
    "auth": {
        "collaboration": {
            "*": {
                "role": "writer"
            }
        }
    }
}

# 对令牌端点的请求

CKEditor 云服务的令牌由 CKEditor 4 和 CKEditor 5 富文本编辑器功能请求,这些功能需要云服务才能工作,例如 轻松图片实时协作编辑

# 简单用法

# CKEditor 5

请求令牌端点的最简单方法是将 config.cloudServices.tokenUrl 选项设置为端点。它将在初始化阶段由 云服务插件 通过在编辑器中使用简单的 HTTP 请求进行请求,然后每小时请求一次。

ClassicEditor.create( element, {
    // ...
    cloudServices: {
        tokenUrl: 'https://example.com/cs-token-endpoint'
    }
} );

如果您需要对请求进行更多控制,请参阅下面的 自定义令牌请求方法 部分。

# CKEditor 4

请求令牌端点的最简单方法是将 cloudServices_tokenUrl 选项设置为端点。它将通过在初始化阶段使用简单的 HTTP 请求从编辑器中发出请求,然后每小时再次请求一次。

CKEDITOR.replace( 'editor', {
    cloudServices_tokenUrl: 'https://example.com/cs-token-endpoint',
} );

您可以在 轻松图片集成指南 中找到有关与 CKEditor 4 集成的更多信息。

# 自定义令牌请求方法

# CKEditor 5

如果您想更改从服务器请求令牌的默认方法(在上一节中描述),您可以将 config.cloudServices.tokenUrl 选项设置为回调。此回调将由 云服务插件 用于检索令牌。它允许为应返回令牌值的令牌端点指定确切的 HTTP 请求参数。回调需要返回一个 promise,该 promise 将使用令牌值解析或使用错误拒绝。

请注意,在从令牌端点获取第一个令牌之前,编辑器将无法使用。如果在初始请求期间发生错误,编辑器将无法正常启动。

以下示例展示了将自定义回调设置为 tokenUrl 配置,该配置向请求添加自定义标头

const tokenUrl = 'https://example.com/cs-token-endpoint';

ClassicEditor.create( element, {
    // ...
    cloudServices: {
        tokenUrl: () => {
            return new Promise( ( resolve, reject ) => {
                const xhr = new XMLHttpRequest();

                xhr.open( 'GET', tokenUrl );

                xhr.addEventListener( 'load', () => {
                    const statusCode = xhr.status;
                    const xhrResponse = xhr.response;

                    if ( statusCode < 200 || statusCode > 299 ) {
                        return reject( new Error( 'Cannot download a new token!' ) );
                    }

                    return resolve( xhrResponse );
                } );

                xhr.addEventListener( 'error', () => reject( new Error( 'Network error' ) ) );
                xhr.addEventListener( 'abort', () => reject( new Error( 'Abort' ) ) );

                xhr.setRequestHeader( customHeader, customValue );

                xhr.send();
            } );
        }
    }
} );

当前令牌值可通过 CloudServices 插件访问。

const cloudServices = editor.plugins.get( 'CloudServices' );
const tokenValue = cloudServices.token.value;

# 令牌端点的响应

端点应以字符串形式响应生成的令牌。

示例响应可能如下所示

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiSm9obiJ9.3MOd-0xmppWAX_86vMPjQ0PTKAniCtr762UTM5WuGa8

# 工具

我们强烈建议您使用 jwt.io 上列出的库来创建令牌。您还可以查看我们在以下语言中的令牌端点实现示例

如果您在其他服务器端语言中创建令牌端点时遇到问题,或者您对文档有任何其他建议,请 联系我们

# 最常见问题

# 无效令牌

CKEditorError: cloud-services-internal-error: Invalid token. Error Trace id: <TRACE ID>. Read more: <https://ckeditor.npmjs.net.cn/docs/ckeditor5/latest/framework/guides/support/error-codes.html#error-cloud-services-internal-error> {"errors":[]}

检查令牌是否根据我们的 标准 创建。您也可以参考我们的 令牌端点示例
请确保您使用的是正确有效的 访问密钥,并且该密钥已分配到正确的环境。
您可以使用 jwt.io 调试器 验证令牌。

# 您没有足够的权限访问此资源

CKEditorError: cloud-services-internal-error: You don't have enough permissions to access this resource. Error Trace id: <TRACE ID>. Read more: <https://ckeditor.npmjs.net.cn/docs/ckeditor5/latest/framework/guides/support/error-codes.html#error-cloud-services-internal-error> {"errors":[]}

请确保您的令牌端点包含请求资源所需的正确角色。
您可以在 角色指南 中了解有关角色机制的更多信息。