Meteor Fan (日本語情報)

JavaScriptフレームワークMeteorに関していろいろ紹介する日本語情報サイト

Meteorで初めてのパーミッション制御

本記事は公式チュートリアル10の内容に沿って説明するものです。

チュートリアルの目次

  1. 初めてのMeteorアプリ作成
  2. 初めてのMeteor Spacebarsでテンプレート
  3. 初めてのMeteor Mongoコレクション
  4. 初めてのフォームとイベント処理
  5. Meteorで初めてのコレクション更新と削除
  6. 初めてのMeteorアプリのデプロイ
  7. Meteorで初めてのモバイルアプリ (スキップ)
  8. Meteorで初めてのセッション変数
  9. Meteorで初めてのユーザアカウント
  10. Meteorで初めてのパーミッション制御 (←今ここ)

これまでのmongoデータベースのパーミッション

上記の一連のチュートリアルにおいては、これまでのところmongoに誰でもアクセスできるようになっていました。完全にオープンです。ユーザ認証機能を加えたことでもこれは変わりません。例えば、ログイン前はタスクを登録できないようにフォームを非表示にしましたが、実際にはJavaScriptのコードを直接実行すればログインしなくてもタスクが登録できてしまいます。

ただし、これは一概に悪いことではありません。そのようなセキュリティモデルであることを正しく理解して使う分には価値があります。例えば、開発途中のアプリで外部に公開しないもの、一人だけで使うアプリ、寿命が極端に短いアプリ、何かしらの方法で別のセキュリティモデルを提供しているアプリなど、利用シーンは様々です。

mongoデータベースのパーミッションを制御する

この完全にオープンなパーミッションは、実はデフォルトで追加されているinsecureというパッケージによって実現されています。よってこのパッケージを削除すると、パーミッションはオープンではなくなり自分で制御することになります。

さて、パッケージを削除してみましょう。meteorを起動している状態で、

meteor remove insecure

を実行してください。パッケージが削除されると、今までできていたタスクの追加などができなくなっているはずです。この時点で動作を確認しましょう。

Meteor.methodsを定義する

クライアント側で直接データを修正することができなくなったので、データを修正するAPI(methods)を用意してクライアントから呼び出せるようにします。その際にmethodsの内部でログインしているかなどの権限をチェックすればよいことになります。

少しややこしいのですが、このmethodsはサーバ側とクライアント側両方に動作するように定義することができます。そうすることで、クライアントではサーバにリクエストを送ると同時に定義されたmethodを実行します。そうすることでサーバの処理の結果を待たずに処理を完了してUIに反映することができます。これをOptimistic UIと呼びます。後ほどサーバからの処理結果が反映されたら再度それをUIに反映します。このとき、結果が同じであればUI上は変化がないため、ユーザからはとても反応のよいUIに見えることになります。

さて、methodsを定義しましょう。sample-app.jsの最後に下記のコードを追加してください。isClientブロックの外に書いてください。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Meteor.methods({
addTask: function (text) {
if (! Meteor.userId()) {
throw new Meteor.Error("not-authorized");
}
Tasks.insert({
text: text,
createdAt: new Date(),
owner: Meteor.userId(),
username: Meteor.user().username
});
},
deleteTask: function (taskId) {
Tasks.remove(taskId);
},
setChecked: function (taskId, setChecked) {
Tasks.update(taskId, { $set: { checked: setChecked} });
}
});

addTaskの初めにログインのチェックが加わりました。これにより、ログインしていないユーザからのアクセスを確実に拒否することができます。

methodsを呼び出す

次に、これらのmethodsを呼び出すようにクライアント側のコードを修正します。

sample-app.jsのisClientブロック内のTasks.insert()文は、

Meteor.call("addTask", text);

になります。同じく、Tasks.update()文は、

Meteor.call("setChecked", this._id, ! this.checked);

になります。同じく、Tasks.remove()文は、

Meteor.call("deleteTask", this._id);

になります。

すべての修正が完了したファイルは、こちらのJavaScriptファイルのようになっているはずですので、確認してください。

動作確認

今回の修正でこれまでと同じように正しく動くか確認しましょう。タスクの追加、タスクの変更・削除ができるはずです。

ログインしていない場合にタスクが追加できないことを確認するには、一旦、フォームをログインしていなくても表示するように変更を戻してから、試してみるとよいでしょう。具体的には、

1
2
3
{{#if currentUser}}
...
{{/if}}

のifの開始と終了のそれぞれ1行を一時的に削除することで戻すことができます。

確認項目

  • addTaskメソッドが定義されていること
  • addTaskメソッドが正しく例外処理すること
  • deleteTaskメソッドが定義されていること
  • setCheckedメソッドが定義されていること

まとめと次のステップ

今回はパーミッションを完全オープンではなく独自に制御する方法を学びました。ここはMeteorの複雑な部分でもあり、すぐに全体を見通すことは難しいかもしれません。しかし、重要な部分でもあるため、時間をかけて理解する必要があるでしょう。

次回は最後のデータの読み込み権限に関する改善について学びます。

おまけ

実は、Meteor.methods以外にもパーミッションを制御する方法があります。collection.allowとcollection.denyです。これらは、ある利用シーンにおいては、比較的手軽に制御することができます。しかし、現在(2015/8/13)の公式チュートリアルでは言及されていないので割愛しました。詳しくは、ドキュメントをご覧ください。