Express.jsでのロールベースの承認に適した戦略は何ですか?特にエクスプレスリソースとは?
Express-resource の場合、ハンドラーがないため、3つのオプションがあると思います。
他の解決策はありますか?
グループ/ロールベースの認証は、かなり古いアプローチです。アクセス制御の新しい方法はありますか?そうでない場合、役割ベースの承認をnode.jsにどのように適用できますか? (NoSQL/CouchDB/Redisを使用して)グループとルールの関係をどこに保存しますか?
例として、構造:
/
/forums
/forums/threads
インデックス付きの各リソース、新規、作成、表示、編集、更新、破棄。スレッドやフォーラムなどを編集/削除できる人もいれば、そうでない人もいます。
Connect-roles は非常にシンプルで、ドキュメントも非常に明確です。
var user = roles;
app.get('/profile/:id', user.can('edit profile'), function (req, res) {
req.render('profile-edit', { id: req.params.id });
})
app.get('/admin', user.is('admin'), function (req, res) {
res.render('admin');
}
ルート固有のミドルウェアが(少なくともクリーンな方法で)許可されていないため、express-resourceを使用してクリーンな方法でこれを解決するのは難しいと思います。
私はExpress-Resourceモジュールと同様のレイアウトを選択しますが、それをプレーンな古いExpressでルーティングします。このようなもの:
// Resource
var forum = {
index: // ...
show: // ...
create: // ...
update: // ...
destroy: // ...
};
// Middleware
var requireRole = function(role) {
return function(req, res, next) {
if('user' in req.session && req.session.user.role === role)
next();
else
res.send(403);
}
};
// Routing
app.get('/forums', forum.index);
app.get('/forums/:id', forum.show);
app.post('/forums', requireRole('moderator'), forum.create); // Only moderators can create forums
app.delete('/forums/:id', requireRole('admin'), forum.destroy); // Only admins can delete forums
UPDATE:express-resource内のルート固有のミドルウェア、たとえば ここ 。一般的なビューは、アクションごとに配列を持っているようです、例えば:
var forums = {
index: [ requireRole('foo'), function(req, res, next) { ... } ]
};
プルリクエストを調べて、使用できるものがあるかどうかを確認できます。もちろん、それが気に入らなければ、私はそれを完全に理解しています。将来的にはExpress-Resourceでこのようなものが表示されると確信しています。
私が考えることができる他の唯一の解決策は、Jan Jongboomの回答に沿ったものです。これは、リソースをexpress-resourceでマウントしますが、ミドルウェアをその「外部」に接続します。
app.delete('*', requireRole('admin')); // Only admins are allowed to delete anything
app.put('/forums/*', requireRole('moderator')); // Only moderators are allowed to update forums
しかし、私はこれがURLをあちこちに漏らしていることを後悔しています。
私は同じ質問を調査していて、いくつかの良いモジュールに出くわしました。ここにあるnode-aclパッケージに焦点を当てています。 https://github.com/optimalbits/node_acl 。
このパッケージはACLパターンを非常に理解しやすい方法で実装しているようで、ノード/エクスプレスアプリケーションに簡単に統合する方法を提供しています。
まず、リソース、ロール、および権限を定義する必要があります。
たとえば、リソースは次のようになります。
/
/forums
/forums/threads
役割は
public
admin
user
john
jane
この例では、johnとjaneの役割は実際のユーザーアカウントにマッピングできますが、ユーザー役割のすべての権限を継承します。
リソースに対する権限
または、標準のCRUD操作。
それらが定義されたので、node-aclを使用してaclを設定する方法を見てみましょう。これらのメモはドキュメントから派生しています
パッケージをインポートする
var acl = require('acl');
バックエンドを設定します。私のアプリはmongodbを使用していますが、node-aclパッケージは他のストレージメカニズムをサポートしています
acl = new acl(new acl.mongodbBackend(dbInstance, prefix));
私のアプリはmongooseを使用しているため、dbInstanceはmongoose.connection.dbに置き換えられます
次に、ACLにロールを追加します。 node-aclでは、ロールに権限を付与することで作成されます。 1つの石で2羽の鳥を殺すようなものです(鳥は実際には害されていません)。
acl.allow('admin', ['/', '/forum', '/forum/threads'], '*');
acl.allow('public', ['/', '/forum', '/forum/threads'], 'show');
acl.allow('user', ['/', '/forum', '/forum/threads'], ['create', 'show']);
新しいリソースがジョンによって作成されたと想定して、ジョンがそのリソースを更新および削除できるようにする新しいレコードを追加します。
acl.allow('john', ['/forum/threads/abc123'], ['update', 'delete']);
私のアプリケーションもExpressを使用しているため、ルーティングミドルウェアアプローチを使用してルートをチェックします。私のルーティング構成では、次の行を追加します
ほとんどの高速構成では、これはposのように見えます
app.post('/', acl.middleware(), function(req, res, next) {...});
app.post('/forums', acl.middleware(), function(req, res, next) {...});
app.post('/forums/:forumId', acl.middleware(), function(req, res, next) {...});
app.post('/forums/threads', acl.middleware(), function(req, res, next) {...});
app.post('/forums/threads/:threadId', acl.middleware(), function(req, res, next) {...});
パラメータが渡されない場合、req.userIdで定義されたロールが、ルートではなく識別されたリソースでhttpメソッドを実行できるかどうかがチェックされます。
この例では、httpメソッドはpostですが、構成で識別される各httpに対して同じことを行います。
これは、以前に定義された許可についての質問を提起します。これらの質問に答えるには、権限を
従来に
この例ではすべてハードコードされていますが、コードを変更することなく動的に作成、読み取り、更新、削除できるように、アクセス許可の管理インターフェイスを用意することをお勧めします。
私はnode-aclプラグインアプローチが好きです。非常に単純で柔軟なAPIを使用して、非常にきめ細かい権限とロールの割り当てを可能にするからです。彼らのドキュメンテーションにはもっとたくさんあります、私の例は私がパッケージを持っていた場合を示しています。
うまくいけば、これが役立ちます。
Expressでは、すべての演算子にフックするハンドラー(http://expressjs.com/guide.html#passing-routeコントロール)を追加できます。ここで、前提条件の検証を行うことができます。ここでは、ユーザーのロールを取得し、HTTP動詞(PUT、DELETEなど)またはURL(param('op')
は「編集」など)に基づいてアクセスを制限できます。
app.all('/user/:id/:op?', function(req, res, next){
req.user = users[req.params.id];
if (req.user) {
next();
} else {
next(new Error('cannot find user ' + req.params.id));
}
});
非明示的なルーティングミドルウェアとしてモジュールを作成しました。高速ルートでうまく機能します。
あなたはCasbinを試すことができます: https://casbin.org/ 、それはNode.jsバージョンを持っています。また、express-authz
というExpress.jsミドルウェアもあります。 https://casbin.org/docs/en/middlewares