Bỏ qua, tới nội dung
Tài liệu APIv1

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ó tokenToken sai hoặc hết hạn
O3O_EMBED_JWT_SECRETnhận401 token_required401 invalid_token / 401 token_expired
Không có khoá, O3O_EMBED_ALLOW_UNSIGNED=1 (DEV)bỏ qua token, dùng config trầnnhậnbỏ qua token, dùng config trần
Không có khoá, O3O_EMBED_ALLOW_UNSIGNED=0401 embed_auth_not_configured401 embed_auth_not_configured401 embed_auth_not_configured

Payload#

Trường của payload

  • documentobjectbắt buộc
    Giống hệt config.document.
  • editorobjectbắt buộc
    Giống hệt config.editor.
  • uiobjecttuỳ chọn
    Giống hệt config.ui.
  • expsố, giây Unixbắt buộc
    Hế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ọn
    Thời điểm ký. Nên có.
JSONPayload trước khi ký
{
  "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ủ#

Ký config
// 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 tokenevents.

JavaScriptTrang nhận token
// 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
    }
  }
});