Step8: セキュリティを高めよう!(Meteor methods)
このステップではMeteorのmethodsについて学びます。
insecure パッケージ
Meteorのアプリを新規作成すると、標準でinsecure
というMeteorパッケージが含まれています。
これは、Webブラウザ側でMeteorコレクションのCRUD(Create, Read, Update, Delete)操作をできるようにするもので、だれでもコレクションを書き換えることができてしまいます。
クライアント側で勝手にデータを書き換えられては困るので、本番感環境ではinsecure
パッケージを外し、Meteorのmethods
という機能を使用します。
それではMemosコレクション操作をmethods
を使って書き換えてみましょう。
まず、insecure
パッケージを取り除きます。
$ meteor remove insecure
またmethods
の引数バリデーションに使用するaldeed:simple-schema
パッケージを追加します。
$ meteor add aldeed:simple-schema
続いて、Memosコレクション用のmethods
ファイルを作成します。
$ touch imports/api/memos/methods.js
imports/api/memos/methods.js
import { Meteor } from 'meteor/meteor';
import { SimpleSchema } from 'meteor/aldeed:simple-schema';
import { Memos } from './memos';
Meteor.methods({
'Memos.insert'(content) {
new SimpleSchema({
content: { type: String }
}).validate({ content });
this.unblock();
Memos.insert({content});
},
'Memos.update'(memoId, content) {
new SimpleSchema({
memoId: { type: String },
content: { type: String }
}).validate({ memoId, content });
this.unblock();
Memos.update({_id: memoId}, {$set: {content}});
},
'Memos.remove'(memoId) {
new SimpleSchema({
memoId: { type: String }
}).validate({ memoId });
this.unblock();
Memos.remove(memoId);
}
});
サーバーでmethods
が実行できるようにmethods
ファイルを読み込みます。
server/main.js
import { Meteor } from 'meteor/meteor';
import { Memos } from '../imports/api/memos/memos';
import '../imports/api/memos/methods';
Meteor.startup(() => {
if (Memos.find().count() === 0) {
const data = [
{content: 'Memo 1'},
{content: 'Memo 2'},
{content: 'Memo 3'},
{content: 'Memo 4'},
{content: 'Memo 5'},
];
data.forEach(memo => Memos.insert(memo));
}
});
クライアント側からのコレクション操作を無効にするため、MemosコレクションにMeteor.deny()
を設定します。
imports/api/memos/memos.js
import { Mongo } from 'meteor/mongo';
class MemosCollection extends Mongo.Collection {
insert(doc, callback) {
doc.createdAt = doc.createdAt || new Date();
const result = super.insert(doc, callback);
return result;
}
}
export const Memos = new MemosCollection('Memos');
Memos.deny({
insert() { return true; },
update() { return true; },
remove() { return true; },
});
// for debug
if (Meteor.isDevelopment) {
global.collections = global.collections || {};
global.collections.Memos = Memos;
}
最後にAppContainerのコレクション操作を行っている部分をmethods
をMeteor.call
で呼び出すように変更します。
imports/ui/containers/AppContianer.js
import AppLayout from '../layouts/AppLayout';
import { Memos } from '../../api/memos/memos';
import { createContainer } from 'meteor/react-meteor-data';
import { Meteor } from 'meteor/meteor';
const createMemo = content => {
Meteor.call('Memos.insert', content);
};
const removeMemo = memoId => {
Meteor.call('Memos.remove', memoId);
};
const updateMemoContent = (memoId, content) => {
Meteor.call('Memos.update', memoId, content);
};
export default createContainer(() => {
return {
memos: Memos.find({}, {sort: {createdAt: -1}}).fetch(),
createMemo,
removeMemo,
updateMemoContent,
};
}, AppLayout);
コードを書き換えたらメモの追加、削除、更新ができることを確認しましょう。
なお、insecure
パッケージを取り除いたことにより、クライアント側でコレクションに対してinsert
, update
, remove
を実行するとエラーが発生するようになりました。
Webブラウザのインスペクタのコンソールで以下のコードを実行することで、挙動を確かめることができます。
collections.Memos.insert({content: 'New Memo'})
// => insert failed: Access denied
Meteor methods について詳しく知りたい方は、Meteor公式のReactチュートリアルおよびMeteor GuideのSecurityの章をご参照ください。
次のステップに進みましょう。