0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

React フロントエンド実践:JavaScript で Excel ブックの保護と保護解除を実装する

0
Posted at

BtoB 向けの業務システム開発では、フロントエンドで Excel ファイルの生成やエクスポートを扱う機会が多くあります。基本的なデータ出力に加えて、ワークブック全体の暗号化、ワークシートの編集権限制限、既存の保護解除など、ファイルにセキュリティ制御を施したいケースも存在します。本記事では、Spire.XLS for JavaScript を使用して、React プロジェクト内でこれらの操作を JavaScript で実装する方法を詳しく解説します。

環境構築

まず、npm で依存パッケージをインストールします:

npm i spire.office

インストール完了後、React コンポーネント内で WASM モジュールを読み込みます。このライブラリは WebAssembly で動作するため、最初にエンジンを非同期でロードする必要があります。一般的な方法として、useEffect 内で初期化を行い、useState でロード状態を管理して後続操作の実行可否を制御します:

import React, { useState, useEffect } from 'react';

function App() {
  const [wasmModule, setWasmModule] = useState(null);

  useEffect(() => {
    (async () => {
      try {
        const publicUrl = process.env.PUBLIC_URL || '';
        const spireModule = await import(/* webpackIgnore: true */ `${publicUrl}/spire.xls.js`);
        const rawModule = spireModule.default || spireModule;
        window.wasmModule = typeof rawModule === 'function'
          ? await rawModule({ locateFile: p => p.endsWith('.wasm') ? `${publicUrl}/${p}` : p })
          : rawModule;
        setWasmModule(window.wasmModule);
      } catch (error) {
        console.error('WASM モジュールの読み込みに失敗しました:', error);
      }
    })();
  }, []);

  // 後続の操作用メソッドはここで定義します...
}

ここでは動的 import を使って spire.xls.js を読み込み、WASM ファイルのパスを指定しています。ロード成功後、モジュールインスタンスを window.wasmModule に格納し、後続の呼び出しを容易にします。wasmModule 状態はボタンのクリック可否を制御し、エンジンの準備が整う前に操作が発生するのを防ぎます。

操作前の準備作業

実際に Excel ファイルを処理する前に、ライブラリの仮想ファイルシステム(VFS)に事前に読み込んでおく必要があるリソースが2つあります。フォントファイルと処理対象の Excel ファイルです。フォントファイルはドキュメント内のテキストを正しくレンダリングするために使用され、Excel ファイルは操作対象のデータソースとなります。

// フォントを VFS に読み込み
await window.spire.FetchFileToVFS('Arial.ttf', '/Library/Fonts/', `${process.env.PUBLIC_URL}/static/font/`);

// Excel ファイルを VFS に読み込み
const inputFileName = 'sample.xlsx';
await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/static/data/`);

FetchFileToVFS の3つの引数は順に、ファイル名、VFS 内の保存先ディレクトリ、ブラウザ側のソースファイルパスです。上記コードでは、フォントファイルが public/static/font/ ディレクトリに、Excel ファイルが public/static/data/ ディレクトリに保存されていることを想定しています。開発者は実際のプロジェクト構成に応じてパスを調整してください。

パスワードでワークブック全体を保護する

ワークブックレベルの保護は、ファイルを開く際にパスワードの入力を要求します。ファイルへのアクセス権限を制御したい場合に適しています。以下は完全な処理関数です:

const EncryptExcel = async () => {
  const wasmModule = window.wasmModule.spirexls;

  if (wasmModule) {
    // フォントとソースファイルを VFS に読み込み(ここでは省略、実際の開発では保持してください)
    // ...

    // ワークブックインスタンスを作成してファイルを読み込み
    const workbook = new wasmModule.Workbook();
    workbook.LoadFromFile(inputFileName);

    // パスワードでワークブックを暗号化
    workbook.Protect('password');

    // 出力ファイル名を定義して保存
    const outputFileName = '暗号化Excelファイル.xlsx';
    workbook.SaveToFile({ fileName: outputFileName, version: wasmModule.ExcelVersion.Version2010 });

    // VFS から生成されたファイルを読み取り、Blob に変換してダウンロード
    const modifiedFileArray = window.dotnetRuntime.Module.FS.readFile(outputFileName);
    const modifiedFile = new Blob([modifiedFileArray], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' });

    const url = URL.createObjectURL(modifiedFile);
    const a = document.createElement('a');
    a.href = url;
    a.download = outputFileName;
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);

    // WASM リソースを解放
    workbook.Dispose();
  }
};

全体の流れは5つのステップにまとめられます:ファイルを VFS に読み込み → Workbook インスタンスを作成 → Protect を呼び出してパスワードを設定 → ファイルを保存 → VFS から読み出してダウンロード。SaveToFileversion パラメータは出力ファイルの Excel バージョン形式を指定します。ここでは Version2010 すなわち .xlsx 形式を使用しています。操作完了後に Dispose を呼び出すことは、WebAssembly が占有するメモリを適時に解放する良い習慣です。

特定の権限でワークシートを保護する

ファイル全体を暗号化するのではなく、特定のワークシートに対するユーザーの操作を制限したい場合もあります。例えば、データレポートを配布する際に、閲覧は許可するが編集は禁止するといったケースです。このような場合は、ワークシートの保護タイプを設定することで細かな制御が可能です:

const EncryptExcelWorksheet = async () => {
  const wasmModule = window.wasmModule.spirexls;

  if (wasmModule) {
    // フォントとソースファイルを VFS に読み込み(ここでは省略)
    // ...

    const workbook = new wasmModule.Workbook();
    workbook.LoadFromFile(inputFileName);

    // 最初のワークシートを取得
    const sheet = workbook.Worksheets.get(0);

    // 特定の権限でワークシートを保護
    sheet.Protect({ password: '123456', options: wasmModule.SheetProtectionType.None });

    // 保存してダウンロード(上記のダウンロードロジックと同じ、ここでは省略)
    // ...

    workbook.Dispose();
  }
};

ここでの重要なパラメータは SheetProtectionType です。例では None を使用して、すべてのユーザー操作を禁止しています。このライブラリは他の保護タイプも提供しており、開発者は必要に応じて組み合わせて使用できます。例えば、書式設定のみ禁止してデータ選択は許可するといった設定が可能です。このような細かい権限設定は、標準化されたデータ収集テンプレートを作成する際に非常に実用的です。

ワークシートの保護を解除する

ファイルを再編集する必要がある場合、正しいパスワードを使用してワークシートの保護を解除できます:

const UnprotectExcelWorksheet = async () => {
  const wasmModule = window.wasmModule.spirexls;

  if (wasmModule) {
    // 保護された Excel ファイルを VFS に読み込み
    const inputFileName = '暗号化Excelワークシート.xlsx';
    await window.spire.FetchFileToVFS(inputFileName, '', `${process.env.PUBLIC_URL}/static/data/`);
    const workbook = new wasmModule.Workbook();
    workbook.LoadFromFile(inputFileName);

    // 保護を解除するワークシートを取得
    const sheet = workbook.Worksheets.get(0);

    // 正しいパスワードで保護を解除
    sheet.Unprotect('password');

    // 保存してダウンロード(ここでは省略)
    // ...

    workbook.Dispose();
  }
};

保護解除後に保存された新しいファイルは、ワークシートの編集制限を受けなくなります。注意すべき点として、パスワードが誤っている場合、Unprotect メソッドは例外をスローします。本番環境では、try-catch を使用して例外を捕捉し、ユーザーに適切なメッセージを表示することをお勧めします。

コンポーネント統合例

上記の機能を1つの React コンポーネントに統合した場合の完全なレンダリング構造は以下の通りです:

return (
  <div style={{ textAlign: 'center', height: '300px' }}>
    <h1>React で JavaScript を使った Excel ワークブックの保護と保護解除</h1>
    <button onClick={EncryptExcel} disabled={!wasmModule}>
      ワークブックを暗号化してダウンロード
    </button>
    <button onClick={EncryptExcelWorksheet} disabled={!wasmModule}>
      ワークシートを保護してダウンロード
    </button>
    <button onClick={UnprotectExcelWorksheet} disabled={!wasmModule}>
      ワークシートの保護を解除してダウンロード
    </button>
  </div>
);

disabled={!wasmModule} により、WASM エンジンの読み込みが完了する前にボタンがクリックできないようにし、早すぎる呼び出しによるランタイムエラーを防ぎます。

技術的ポイントのまとめ

実装プロセス全体を振り返ると、いくつかの重要なポイントがあります:

第一に、WASM モジュールの初期化は非同期プロセスであり、必ず読み込み完了後にファイル操作を行う必要があります。そうしないと、エンジンの準備が整っていないためにエラーが発生します。

第二に、このライブラリは独立した仮想ファイルシステムを使用してファイルを管理します。入力ファイルは事前に FetchFileToVFS でインポートし、出力ファイルは FS.readFile で読み取ってからフォーマットを変換する必要があります。これはブラウザのファイルシステムを直接操作する方法とは考え方が異なります。

第三に、サンプルコードではパスワードが平文で記述されています。プロジェクトのセキュリティ要件が高い場合は、ユーザーがページ上でパスワードを入力する方式に変更し、機密情報がフロントエンドのコードに直接露出するのを避けることをお勧めします。

第四に、各操作の完了後に Dispose を呼び出すことで WebAssembly のメモリ解放に役立ちます。特に複数のファイルを連続して処理するシーンでは、リソース管理に注意を払うべきです。

おわりに

上記の例からわかるように、React フロントエンドプロジェクトで Excel ワークブックとワークシートの保護および保護解除を実装することは可能です。プロセス全体はバックエンドサービスに依存せず、すべてのファイル処理がブラウザ側で完結します。このアプローチは、純粋にフロントエンドでドキュメントを処理する必要があるシーンにおいて一定の実用価値を持ちます。制御されたデータレポートの生成であれ、ユーザー向けのファイル暗号化ツールの提供であれ、本記事で紹介した技術的アプローチは拡張のための参考基盤として活用できます。これらの内容が、フロントエンドでのドキュメント処理の方向性を探求している開発者の方々の参考になれば幸いです。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?