Nhúng trình soạn thảo
Ký cấu hình bằng JWT
Ký config bằng JWT HS256 với O3O_EMBED_JWT_SECRET ở máy chủ Node.js, Python, PHP và C#, và cách trang dùng token.
Trong trang này
Khi chạy thật, mọi config phải được máy chủ của bạn ký, để người dùng không tự đổi document.url, editor.mode hay editor.user trên trình duyệt. O3O dùng JWT HS256 với khoá chung O3O_EMBED_JWT_SECRET (tối thiểu 32 ký tự).
| Cấu hình máy chủ | Có token hợp lệ | Không có token | Token sai hoặc hết hạn |
|---|---|---|---|
Có O3O_EMBED_JWT_SECRET | nhận | 401 token_required | 401 invalid_token / 401 token_expired |
Không có khoá, O3O_EMBED_ALLOW_UNSIGNED=1 (DEV) | bỏ qua token, dùng config trần | nhận | bỏ qua token, dùng config trần |
Không có khoá, O3O_EMBED_ALLOW_UNSIGNED=0 | 401 embed_auth_not_configured | 401 embed_auth_not_configured | 401 embed_auth_not_configured |
Payload#
Trường của payload
documentobjectbắt buộcGiống hệtconfig.document.editorobjectbắt buộcGiống hệtconfig.editor.uiobjecttuỳ chọnGiống hệtconfig.ui.expsố, giây Unixbắt buộcHết hạn, tối đa 24 giờ kể từiat(hoặc từ hiện tại nếu không cóiat). Cho phép lệch đồng hồ 60 giây.iatsố, giây Unixtuỳ chọnThời điểm ký. Nên có.
{
"document": {
"url": "https://files.example.com/contracts/42.docx",
"title": "Hợp đồng số 42.docx",
"fileType": "docx",
"key": "contract-42-v7"
},
"editor": {
"mode": "edit",
"lang": "vi",
"user": {
"id": "u-1001",
"name": "Nguyễn Văn A"
},
"callbackUrl": "https://app.example.com/o3o/callback"
},
"ui": {
"closeButton": true
},
"iat": 1790000000,
"exp": 1790003600
}Ký ở máy chủ#
// npm install jsonwebtoken
const jwt = require("jsonwebtoken");
const config = {
document: { url: "https://files.example.com/contracts/42.docx", title: "Contract 42.docx", fileType: "docx", key: "contract-42-v7" },
editor: { mode: "edit", lang: "vi", user: { id: "u-1001", name: "Jane Doe" }, callbackUrl: "https://app.example.com/o3o/callback" },
ui: { closeButton: true }
};
// jsonwebtoken tự thêm iat; expiresIn đặt exp (tối đa 24 giờ)
const token = jwt.sign(config, process.env.O3O_EMBED_JWT_SECRET, { algorithm: "HS256", expiresIn: "1h" });
console.log(token);# pip install pyjwt
import os
import time
import jwt
config = {
"document": {"url": "https://files.example.com/contracts/42.docx", "title": "Contract 42.docx", "fileType": "docx", "key": "contract-42-v7"},
"editor": {"mode": "edit", "lang": "vi", "user": {"id": "u-1001", "name": "Jane Doe"}, "callbackUrl": "https://app.example.com/o3o/callback"},
"ui": {"closeButton": True},
}
now = int(time.time())
token = jwt.encode({**config, "iat": now, "exp": now + 3600}, os.environ["O3O_EMBED_JWT_SECRET"], algorithm="HS256")
print(token)<?php
// composer require firebase/php-jwt
require __DIR__ . '/vendor/autoload.php';
use Firebase\JWT\JWT;
$config = [
'document' => ['url' => 'https://files.example.com/contracts/42.docx', 'title' => 'Contract 42.docx', 'fileType' => 'docx', 'key' => 'contract-42-v7'],
'editor' => ['mode' => 'edit', 'lang' => 'vi', 'user' => ['id' => 'u-1001', 'name' => 'Jane Doe'], 'callbackUrl' => 'https://app.example.com/o3o/callback'],
'ui' => ['closeButton' => true],
];
$now = time();
$token = JWT::encode($config + ['iat' => $now, 'exp' => $now + 3600], getenv('O3O_EMBED_JWT_SECRET'), 'HS256');
echo $token, PHP_EOL;// dotnet add package Microsoft.IdentityModel.JsonWebTokens
using System.Text;
using System.Text.Json.Nodes;
using Microsoft.IdentityModel.JsonWebTokens;
using Microsoft.IdentityModel.Tokens;
var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
var payload = new JsonObject
{
["document"] = new JsonObject { ["url"] = "https://files.example.com/contracts/42.docx", ["title"] = "Contract 42.docx", ["fileType"] = "docx", ["key"] = "contract-42-v7" },
["editor"] = new JsonObject
{
["mode"] = "edit", ["lang"] = "vi",
["user"] = new JsonObject { ["id"] = "u-1001", ["name"] = "Jane Doe" },
["callbackUrl"] = "https://app.example.com/o3o/callback"
},
["ui"] = new JsonObject { ["closeButton"] = true },
["iat"] = now,
["exp"] = now + 3600
};
// HS256 cần khoá tối thiểu 32 byte, khớp yêu cầu tối thiểu 32 ký tự của O3O_EMBED_JWT_SECRET
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Environment.GetEnvironmentVariable("O3O_EMBED_JWT_SECRET")!));
var token = new JsonWebTokenHandler().CreateToken(payload.ToJsonString(), new SigningCredentials(key, SecurityAlgorithms.HmacSha256));
Console.WriteLine(token);Dùng token ở trình duyệt#
Khi token hợp lệ, gate dùng document, editor, ui trong token và bỏ qua các trường cùng tên gửi kèm bên ngoài. Vì vậy trang chỉ cần gửi token và events.
// Máy chủ của bạn đưa token xuống trang (không bao giờ đưa khoá). Gửi mỗi token là đủ.
const editor = new O3O.Editor("o3o-editor", {
token: "<token do máy chủ ký>",
events: {
onError: (e) => {
if (e.code === "token_expired") location.reload(); // xin token mới
}
}
});