[前回] Web3.0検証(18)-MeteorでTODO管理アプリの開発(Githubアカウントでログイン)
はじめに
今回は、セキュリティ関連のデータ保護機能です。
Meteorメソッドを使用し、データへのアクセスを制御します。
データアクセス制御の必要性
- アプリケーションで、データへのアクセスを制御しないと
- クライアントからデータを直接操作できるなど、セキュリティ上問題となる
Meteorメソッドによるデータ操作
- Meteorメソッドとは、
Meteor.call
関数を使用しサーバーと通信する方法- メソッドの名前と引数を指定する必要あり
- Meteorでメソッドを宣言することで、安全にデータ操作できる
- メソッドを使用し、ユーザーのデータ操作に対し認証/認可を行う
- クライアントからの以下直接呼び出しをブロック
insert
update
remove
準備
-
端末を二つ用意します。
- 端末1: meteor起動/確認
- 端末2: コード修正
-
端末1から、Meteorアプリを実行
$ cd simple-todos-react
$ meteor run
- ブラウザでアプリを確認
-
http://localhost:3000/
にアクセス - デベロッパーツールを開く(F12)
-
デバイスのツールバーを切り替え
アイコンをクリック - デバイスを選択
- 今回は、
iPhone SE
を選択
- 今回は、
-
安全でないパッケージを無効に
-
insecure
パッケージ- クライアントからデータベースを編集可能にできる
- 迅速なプロトタイピングに役立つ
-
端末2から、安全でないパッケージを削除
$ cd simple-todos-react
$ meteor remove insecure
タスクメソッドを追加
-
作業内容
- メソッドを定義
- クライアントで実行するデータベース操作ごとに1つのメソッドが必要
- Optimistic UIをサポートするためには、クライアントとサーバー両方で実行されるコードで定義する必要あり
- Optimistic UI
-
Meteor.call
を使用し、クライアントでメソッドを呼び出すと、次の2つが並行して発生- クライアントはサーバーにリクエストを送信し、安全な環境でメソッドを実行
- メソッドのシミュレーションがクライアントで直接実行され、呼び出しの結果を予測
- サーバーから結果が返される前に、新しく作成されたタスクが実際に画面に表示される
- 予測結果がサーバーの結果と一致する場合、すべてがそのまま残る
- さもなければ、UIはサーバーの実際の状態を反映するため更新される
-
- メソッドを定義
-
コード
-
imports/api
フォルダーにtasksMethods
ファイルを追加- クライアントは、Mini Mongo操作を直接使用する代わりに、これらのメソッドを呼び出す
- メソッド内に、オブジェクトで使用できる特別なプロパティが存在
- たとえば、認証されたユーザーの
userId
- たとえば、認証されたユーザーの
-
check
パッケージを使用し、入力値が期待されるタイプか確認- データベースに対し、何を挿入/更新しているかを正確に把握するために重要
-
imports/api/tasksMethods.js
import { Meteor } from 'meteor/meteor';
import { check } from 'meteor/check';
import { TasksCollection } from './TasksCollection';
Meteor.methods({
'tasks.insert'(text) {
check(text, String);
if (!this.userId) {
throw new Meteor.Error('Not authorized.');
}
TasksCollection.insert({
text,
createdAt: new Date,
userId: this.userId,
})
},
'tasks.remove'(taskId) {
check(taskId, String);
if (!this.userId) {
throw new Meteor.Error('Not authorized.');
}
TasksCollection.remove(taskId);
},
'tasks.setIsChecked'(taskId, isChecked) {
check(taskId, String);
check(isChecked, Boolean);
if (!this.userId) {
throw new Meteor.Error('Not authorized.');
}
TasksCollection.update(taskId, {
$set: {
isChecked
}
});
}
});
- サーバーにこれらのメソッドが登録されているか確認
-
tasksMethods
ファイルをインポート - インポートからシンボルを取得する必要なし
- ファイルをインポートするようにサーバーに要求するだけで
-
Meteor.methods
が評価され、サーバー起動時にメソッドが登録される
-
- ファイルをインポートするようにサーバーに要求するだけで
-
server/main.js
import '/imports/api/tasksMethods';
メソッド呼び出しを実装
- 作業内容
- メソッドを使用するため、コレクションの操作箇所を更新
-
TaskForm
ファイルで-
TasksCollection.insert
の代わりに、Meteor.call('tasks.insert', text);
を呼び出す - インポートも修正
- サーバーで
userId
を取得する-
TaskForm
コンポーネントがユーザーを取得する必要はなくなる
-
-
- コード
imports/ui/TaskForm.jsx
export const TaskForm = () => {
const [text, setText] = useState('');
const handleSubmit = e => {
e.preventDefault();
if (!text) return;
Meteor.call('tasks.insert', text);
setText('');
};
... ...
};
-
App.jsx
ファイルで-
TasksCollection.update
の代わりに、Meteor.call('tasks.setIsChecked', _id, !isChecked);
をコール -
TasksCollection.remove
の代わりに、Meteor.call('tasks.remove', _id)`をコール -
<TaskForm/>
からユーザープロパティも削除
-
imports/ui/App.jsx
import { Meteor } from 'meteor/meteor';
import React, { useState, Fragment } from 'react';
import { useTracker } from 'meteor/react-meteor-data';
import { TasksCollection } from '/imports/db/TasksCollection';
import { Task } from './Task';
import { TaskForm } from './TaskForm';
import { LoginForm } from './LoginForm';
const toggleChecked = ({ _id, isChecked }) =>
Meteor.call('tasks.setIsChecked', _id, !isChecked);
const deleteTask = ({ _id }) => Meteor.call('tasks.remove', _id);
... ...
<TaskForm />
.....
アプリを確認
-
今までの修正のおさらい
- データベースにタスクを挿入すると
- ユーザー認証によるチェックが実行される
- クライアントコードをデータベースロジックから分離
- データ変更は、イベントハンドラーの代わりに、メソッド呼び出しを使用
- データベースにタスクを挿入すると
-
画面から、新しいタスクを登録
タスクが正しく登録できました。やったー。
ファイル配置を変更
-
TasksCollection.js
ファイルをapi
フォルダからdb
フォルダに移動- プロジェクトで
API
は、サーバーとクライアント間の通信レイヤーを意味 -
TasksCollection
コレクションは、上記修正により既にこの役割を果たしていない - ※ ファイルや変数の名前は現実と同じものが推奨される
- プロジェクトで
-
インポートを修正
- 以下四つのファイルに
TasksCollection
へのインポートが存在- imports/api/tasksMethods.js
- imports/ui/TaskForm.jsx
- imports/ui/App.jsx
- server/main.js
- 変更前:
import { TasksCollection } from '/imports/api/TasksCollection';
- 変更後:
import { TasksCollection } from '/imports/db/TasksCollection';
- 以下四つのファイルに
トラブルシューティング
-
Meteor DevToolsを使用
-
check
呼び出しにエラーハンドリングを追加- 間違ったタイプに対し、発生したエラーを追跡できる
おわりに
アプリのセキュリティ対策として、データアクセス制御を追加しました。
次回も続きます。お楽しみに。