令牌端点
# 令牌端点概述
要将 CKEditor 5 或 CKEditor 4 与 CKEditor 云服务连接,您需要创建自己的令牌端点。本指南将解释创建令牌端点所需了解的一些原理。
# CKEditor 云服务如何使用令牌
为了对用户进行身份验证,CKEditor 云服务使用令牌。令牌的目的是通知云服务用户有权访问资源,以及用户应该连接到哪个环境。令牌的真实性由数字签名提供。
令牌端点是使用 CKEditor 的客户端发出获取令牌请求的地方。只有在用户证明其身份的情况下,它才应返回令牌。
令牌端点应放置在您的系统内部。
# JSON Web 令牌规范
CKEditor 云服务令牌表示为 JSON Web 令牌 (JWT)。JWT 是一种开放的 标准,用于传输数字签名的信息。使用它可确保数据来自受信任的来源。
令牌由三部分组成
- 标头
- 有效负载
- 签名
每部分都使用 base64url
编码,并用点号分隔
header.payload.signature
示例令牌可能如下所示
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjoiSm9obiJ9.3MOd-0xmppWAX_86vMPjQ0PTKAniCtr762UTM5WuGa8
# 标头
标头指示它是 JWT,并定义用于计算签名的哈希算法。它只是一个包含 typ
和 alg
属性的 JSON 对象,其中 typ
始终包含 JWT
值,而 alg
包含所用算法的名称。
# 有效负载
有效负载是一个包含声明的 JSON 对象。在 CKEditor 云服务中,它主要用于指定环境、用户数据和权限。
JWT 标准指定了一些预定义的声明,例如 aud
(受众)、exp
(过期时间)、sub
(主体)或 iat
(签发时间)。在 CKEditor 云服务中,我们使用 aud
来识别环境,使用 iat
来检查令牌是否已过期,以及使用 sub
来识别用户。
# 签名
与标头和有效负载不同,签名不是 JSON 对象,而是由加密算法生成的原始字节。
签名是针对合并的标头和有效负载计算得出的。它可以对数据进行身份验证,并验证令牌是否已被篡改。
signature = HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
secret
)
CKEditor 云服务支持由 HS256
、HS384
和 HS512
算法创建的签名。
切勿泄露密钥,因为这将允许伪造令牌。
# 令牌
CKEditor 云服务的令牌应将 环境 ID
指定为 aud
属性,并且需要使用 访问密钥
进行签名。两者都可以在 CKEditor 生态系统客户仪表板(用于 SaaS)或管理面板(用于本地部署)中找到 - 请参阅 环境管理文档。可选地,令牌可以包含用户数据。否则,CKEditor 云服务将把用户视为匿名用户。
# 用户
如果用户不是匿名的,则有效负载应包含 sub
声明,该声明标识用户。您还可以放置一个 user
对象来定义其他属性,如 name
、email
或 avatar
。在匿名用户的情况下,将生成随机用户 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
– 用户信息。建议提供name
和email
。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":[]}
请确保您的令牌端点包含请求资源所需的正确角色。
您可以在 角色指南 中了解有关角色机制的更多信息。