ONLYOFFICE’s diary

OSSドキュメントエディタの使い方やヒントをご紹介します

ONLYOFFICEと文書管理システムとの連携方法、Nextcloudの事例で解説

ONLYOFFICEは、ドキュメント、スプレッドシート、スライドエディタを含む、オープンソースのオフィススイートです。このスイートは、サードパーティのWebアプリと統合して、そのインターフェイス内で使用することができます。

ここで最もポピュラーなケースは、文書管理システム(DMS)との統合だ。ONLYOFFICEが追加できる機能は以下の通りです。

  • テキスト文書、スプレッドシート、スライドの閲覧・編集
  • リアルタイムでの文書共同編集

ONLYOFFICEドキュメントエディタを統合するためには、エディタ(ドキュメントサーバと呼ばれる)とファイルストレージ(DMS)をつなぐ橋渡し役となる統合アプリ(コネクタとも呼ばれる)を作成する必要があります。

今回は、どのように統合を行うのか、DMSからONLYOFFICEにどのような権限を付与するのか、そしてどのように実践するのかを説明します。例として、オープンソースのセルフホスティング型ファイル共有・コミュニケーションプラットフォームであるNextcloudとONLYOFFICEを連携させた場合を紹介します。

統合チェックリスト

DMSからONLYOFFICEに付与されるべき権限の一覧で、この権がないと連携できません。

  1. カスタムコードの追加と実行
  2. ファイルのダウンロードと保存のための匿名アクセス(これは脆弱性のように聞こえるかもしれませんが、そうではなく、後ほどファイルがどのように保護されるかを説明します)。これは、私たちのエディタが、クライアント側からのユーザー承認データ(ブラウザのクッキー)を介さずに、サーバー側で文書管理システムと通信するだけであることを意味します。
  3. UIに新しいボタンを追加(例えば、「ONLYOFFICEで編集する」)。
  4. エディタを追加するためのスクリプトを実行できる新しいページを開く。
  5. ONLYOFFICEドキュメントサーバーの仮想アドレスの指定ができること。

このチェックリストを見ながら、Nextcloud用ONLYOFFICE連携アプリでこれらをどのように利用したかを見ていきましょう。

1. コードの追加

ONLYOFFICEはソースコードの改変をしないので、統合を可能にするためには、カスタムモジュール、プラグイン、パッケージ、アプリを追加できるサービスでなければなりません。

Nextcloudは、サードパーティの開発者が独自のアプリを追加することを可能にしています。すべてのアプリは、ユーザーが簡単にアプリのDMSに必要な拡張機能を取得するために、そのアプリストアで公開されています。ONLYOFFICE連携アプリもそこで入手可能です。また、GitHubソースコードを確認することができるので、自社サービスの連携アプリのサンプルとしてご利用ください。最も重要な部分をご案内します。

なお、NextcloudとそのアドオンはすべてPHPで書かれているので、以下のコードサンプルではPHPプログラミング言語を使用しています。

2. 匿名アクセス

統合アプリ/コネクターのために、コールバックハンドラを記述する必要があります。これは、ONLYOFFICE Document Serverからファイルストレージへのリクエストを処理します。

こちらで文書化されたリクエストパラメータに応じて、ファイルストレージ側で異なるアクションを実行することができます(例えば、ファイルの内容を返す、ファイルを保存する、など)。重要なのは、これがDocument Serverとファイルストレージの間の直接的なやり取りであり、ブラウザのクッキーのようなユーザー認証データを必要としないことで、上で述べたように、これはいかなる意味でも脆弱性ではありません。

ここでのセキュリティは、JWT技術によって構成されており、リクエスシグネチャの検証を行います。ドキュメントサーバーは、設定ファイルにある秘密の単語を使ってリクエストにJWTを追加し、ファイルストレージは、自身の設定ファイルにある秘密の単語を使ってそれをチェックします。コールバックハンドラは、署名の検証が成功した場合のみ、要求されたアクションを実行します。

Nextcloudコネクターのコールバックハンドラーは、特定のURLに対してリクエストが送信されたときに呼び出されます。

"routes" => [
   ["name" => "callback#download", "url" => "/download", "verb" => "GET"],
   ["name" => "callback#track", "url" => "/track", "verb" => "POST"],
   ...
]

受信したリクエストに対して、署名の検証が行われます。

public function checkJWT($token) {
    try {
        $decodedHeader = \Firebase\JWT\JWT::decode($token, $this->getSecret(), array("HS256"));
    } catch (\UnexpectedValueException $e) {
        return false;
    }
return true;
}

ここでは、Document Serverがファイルストレージにファイルコンテンツを要求する方法になります。

class CallbackController extends Controller {
    public function download($doc) {
        If ($this->checkJWT(\OC::$server->getRequest()->getHeader("Authorization")) === false) new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN);
        $file = $this->getFile($doc);
        return new DataDownloadResponse($file->getContent(), $file->getName(), $file->getMimeType());
    }
    ...
}

そして、そのファイルをストレージに保存し直す方法です。

class CallbackController extends Controller {
    public function track($doc, $status, $url, $token) {
        If ($this->checkJWT($token) === false) new JSONResponse(["message" => $this->trans->t("Access denied")], Http::STATUS_FORBIDDEN);
        $error = 1;
        switch ($status) {
            case 2:  //must save
                $file = $this->getFile($doc);
                if (($newData = $this->Request($url))) {
                    $file->putContent($newData);
                    $error = 0;
                }
                break;

            case 1:  //editing
            case 4:  //closed
                $error = 0;
                break;
        }
        return new JSONResponse(["error" => $error], Http::STATUS_OK);
    }
    ...
}

以下の反応をするはずです。

{”error”: 0}

3. ボタンの追加

エンドユーザーにとって、ONLYOFFICEでの作業は、「開く」、「編集」、「新規作成」、「変換」などのボタンで始まります。このアクションは、より正確に言うと、特定のファイルタイプに関連付けることができます。

  • 閲覧:DOCX、XLSX、PPTX、CSV、TXT、PDF
  • 編集:DOCX、XLSX、PPTX、CSV、TXT
  • 新規作成:DOCX、XLSX、PPTX
  • Office Open XML形式(DOCX、XLSX、PPTX)への変換:DOC、DOCM、DOT、DOTX、EPUB、HTM、HTML、ODP、ODT、POT、POTM、POTX、PPS、PPSM、PPX、PPT、PPTM、RTF、XLS、XLSM、XLT、XLTM、XLTX

(また、ユーザーが持つアクセス権の種類も考慮する必要があります)

Nextcloudでは、クライアントサイドでスクリプトを実行することも、コンテキストメニューにボタンを追加することもできます。このように、DOCXファイルを開くためのボタンを作成します。

fileList.fileActions.registerAction({
    name: "onlyofficeOpen",
    displayName: "Open in ONLYOFFICE",
    mime: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
    permissions: OC.PERMISSION_READ,
    iconClass: "icon-onlyoffice-open",
    actionHandler: function(fileName, context) {
            window.open(OC.generateUrl("/apps/onlyoffice/" + context.fileInfoModel.id);
        }
});

4. エディタのページを開く

ユーザーがアクションボタンをクリックすると、新しいエディタのページの初期化設定が生成されます。この段階で、ファイルを開くことができるかどうか、ユーザーのアクセス権をチェックします。

それに加えて、インターフェイスオプションのような、エディタのための追加パラメータをいくつか送信します。たとえば、document.permissions.download = falseは、エディタからファイルのダウンロードボタンを削除し、editorConfig.lang = "de-DE"は、インターフェイス言語をドイツ語に変更します。

Nextcloudでは、このメカニズムは別のリクエストハンドラとして実装されています。

class EditorController extends Controller {
    public function config($fileId) {
        $file = $this->getFile($fileId);

        $fileName = $file->getName();
        $ext = strtolower(pathinfo($fileName, PATHINFO_EXTENSION));

        $formats = [
            "docx" => [ "type" => "word" ],
            "xlsx" => [ "type" => "cell" ],
            "pptx" => [ "type" => "slide" ]
        ];

        $params = [
            "document" => [
                "fileType" => $ext,
                "key" =>  $this->getKey($file),
                "title" => $fileName,
                "url" => $this->getUrl($fileId),
            ],
            "documentType" => $format[$ext]["type"]
        ];

        if ($file->isUpdateable()) {
            $params["editorConfig"]["callbackUrl"] = $this->urlGenerator->linkToRouteAbsolute($this->appName . ".callback.track", ["doc" => $fileId]);;
            $params["editorConfig"]["mode"] = "edit";
        } else {
            $params["editorConfig"]["mode"] = "view";
        }

        return $params;
    }
    ...
}

複数のユーザーが同じドキュメントで同時に作業することができます。この場合、1つのNextcloudインスタンスで、複数のユーザーが開いた同じファイルに対して、同じdocument.keyを使うことで共同編集を実現します。

private function getKey($file) {
    $instanceId = $this->config->getSystemValue("instanceid");
    $key = $instanceId . "_" . $file->getId() . "_" . $file->getMtime();
    return $key;
}

不要な変更から設定を保護するために、JWT署名を追加しています。

$params["token"] = \Firebase\JWT\JWT::encode($params, $this->config->GetDocumentServerSecret());

5. アプリの設定

統合アプリは、グローバル(ドキュメントサーバーのアドレス)およびユーザーごと(ユーザー設定)の設定を取得する必要があります。アプリの設定は、サーバーサイドの設定ファイルを使うか、Web設定ページ全体を作成することで行います。Nextcloud ONLYOFFICEでは、管理者設定ページで接続設定が可能です。

ONLYOFFICE-Nextcloud連携の仕組みについては、APIドキュメントで詳しくご紹介します。

この記事から得た原則をもとに、あなた自身の統合アプリを作成していただければと思います。NextcloudコネクタのソースコードPHP)とは別に、他の連携アプリのソースコードも確認してください。

もしあなたがONLYOFFICEを他の言語で書かれたアプリと統合する気があるなら、これらのテスト例(最もシンプルな文書管理システム)をチェックして、エディタがそれらとどのように動作するかを確認するか、エディタをNode.jsアプリに統合する方法についての記事を読んでみてください。

DOCX, XLSX, PPTX編集を追加することで恩恵を受ける文書管理システムをご存知の方は、コメントで共有してください。