node_acl権限管理パスパスパスパスパスパス
26603 ワード
最近nodejsベースの権限管理をして、1、2日調べてみると、passportjsnode-oauthrbacnode_aclexpress_aclconnect-roles
需要モジュール、ページ、APIなどのレベルに従って権限制御を行い、一時的にボタンレベル を行う必要はない.主なプログラムの開発が完了し、侵入が少ない が必要である.ストレージは主にredis を考慮する.自分で管理ページを開発し、 のカスタマイズとメンテナンスを容易にする.
選択の原則軽量クラスpassportjsは強すぎて、 を恐れるほど大きい.ドキュメントクリア(例|API)node_aclのreadme私はただ、本当にとても友好的で、APIも多くありませんが、すべてとてもgetして に着きました.好手 容易拡張 機能が強力または適用可能 コード侵入が少なくコードの修正が嫌い 人気指数は比較的高い 最後にnode_を選択しましたacl、主にの人気は比較的高く、約2000 star、 次に機能自体が独立し、メモリ、mongo、redisの3つの記憶方式 を提供する. API簡単で使いやすい ドキュメント読みやすい ソースコードは多くなく、 のカスタマイズと拡張が便利です.私達の主要なプログラムは開発し終わって、侵入が少なくて、研究した後にnodeを発見しますaclは できるはずです
node_の確認aclの後、いくつかの小さな細部と設計を研究し始め、こんなに多くのことを言って、自分でコードを書いてインタフェースの機能テストを行います.
質問リスト:権限はaddRoleParentsを継承して需要を満たし、確かに使いやすい.例えばguest,user,adminの3つのRole,user集積guest,admin集積userである.次に、異なるロールに対してパーミッション構成を行います.悪くない Resourceは同梱をサポートしていません.これはどういう意味ですか.例えば、メッセージには次のパスがあります./msg/delete、msg/add、/msg/list、犬の血Added the possibility to have a wildcard in resource name すべてのRoleクエリーのAPIを提供していません.私が入った後、どのくらいのRole があるか分かりません.キャラクターを削除すると、 のデータが残ります.は、ページまたはAPI を関連付けるモジュールを導入する必要がある初期化には、スーパー管理者 が必要です.デフォルト設定、すべて許可?すべてアクセスできませんか? ディレクトリ継承関係を導入するかどうか . ......
ここはスリスリがこんなにたくさん書いていて、APIさえできれば、残りはデザインの問題です.面倒な問題が来た Resourceは、プロビジョニング をサポートしていません.すべてのロールクエリを提供しないAPI この2つの基本的な機能はサポートされておらず、卵も游んでいます.落ち着いて、落ち着いて、私たちはソースコードを開けて、プラグインは全部で7つのjs(バージョン0.4.11) acl.jsコアのコアファイル、ロール、Resource、PermissionなどのAPI の暴露 backend.js backend API定義、実用的な役割はありません contract.jsパラメータ検証js memory-backend.jsメモリに を格納 mongodb-backend.js mongodbストレージ redis-backend.js redisストレージ index.jsデフォルトファイル 3つのbackendはすべてデータを格納しているので、まずデータをエクスポートしてみましょう.redisのエクスポート方法について見てみましょう. redis-dump をインストール edis-dump -h 127.0.0.1 -d 0 --json > c:\db.json
エクスポートされたファイルを見てみましょう aclは接頭辞で、aclを初期化するときに設定できます
acl_meta@roles,acl_meta@users,acl_meta@usersacl_meta@rolesは格納されているすべてのRoleを表し、他の同理はコードaclにひっくり返す.jsはシステムがどのようにあるユーザーのRolesの を取るかを見てみましょう.
this.options.buckets.usersは何者だ?
this.options.buckets.users:usersテキストです.では、これらのパラメータ「acl」、「users」、「1024」を連想します.驚いたかどうか見てみましょう.意外です.
簡単だよjsにはbucketKeyという方法があります.専門ユーザーが格納しているkeyをつなぎ合わせるので、どんなデータを手に入れたいのか、考え方は簡単です.
現在のすべてのロールを取得し、どのように取得するかは、主にスーパー管理者に与えられます.接合部aclだけでmeta@rolesを選択すると、すべてのキャラクタを取得できます.
これまで,データ構造を解析した後,多くのインタフェースが露出していないデータを得ることができた.私たちが最も関心を持っている問題に戻って、これは通マッチングをサポートしていません.どうすればいいですか?? Mongodb-backendプロジェクトは主にredisを考慮し、これは を考慮しない.プラグインがクエリーしましたnode_aclのプラグインはいくつかありますが、より多くのストレージをサポートする のようです.カスタム拡張 ディレクトリ権限継承これは を考慮することができる.手動メンテナンス、aclに協力する.middlewareの最初のパラメータは、ディレクトリを限定するのは気まずい です. Acl.middleware+追加開発ミドルウェア()の修正が多く、感じが悪い await next()の後、戻る前に再び邪魔な考えをブロックします ここでは、カスタム拡張を考慮して、APIを静かに見てみましょう. userId => roles (userRoles) roles=>resources|実際の条件に基づいてキャッシュ(whatResources) resourcesでpathをマッチングし、条件を満たすresources|resource を検索する一致するresourceクエリーアクセス権(isAllowed) 1,2,4はいずれも既存のAPIがあり,3だけが自分で実現しなければならないが,ここではpath-to-regexpについて言及し,expressとkoaはこれに基づいてルーティングマッチングを表示しているので,私は上記の考えを持っている.
これは現在pathマッチングを要求しているすべてのResourceを取得することができ、複数である可能性が高いので、どのようにすれば、いずれのマッチングも可能であるはずです.最後のコードは
どのように使うか、権限設定 ミドルウェアブロック 権限の設定
ミドルウェアブロック
Node acl demonode権限制御モジュールnode_aclの応用
需要
選択の原則
node_の確認aclの後、いくつかの小さな細部と設計を研究し始め、こんなに多くのことを言って、自分でコードを書いてインタフェースの機能テストを行います.
質問リスト:
ここはスリスリがこんなにたくさん書いていて、APIさえできれば、残りはデザインの問題です.面倒な問題が来た
エクスポートされたファイルを見てみましょう
{
"acl_allows_/@guest": {
"type": "set",
"value": [
"*"
]
},
"acl_allows_/about@guest": {
"type": "set",
"value": [
"*"
]
},
"acl_allows_/index@guest": {
"type": "set",
"value": [
"*"
]
},
"acl_meta@roles": {
"type": "set",
"value": [
"guest"
]
},
"acl_meta@users": {
"type": "set",
"value": [
"1024"
]
},
"acl_resources@guest": {
"type": "set",
"value": [
"/",
"/about",
"/index"
]
},
"acl_roles@user": {
"type": "set",
"value": [
"1024"
]
},
"acl_users@1024": {
"type": "set",
"value": [
"user"
]
}
}
var acl = require('acl');
// Using redis backend
acl = new acl(new acl.redisBackend(redisClient, 'acl'));
/**
userRoles( userId, function(err, roles) )
Return all the roles from a given user.
@param {String|Number} User id.
@param {Function} Callback called when finished.
@return {Promise} Promise resolved with an array of user roles
*/
Acl.prototype.userRoles = function(userId, cb){
return this.backend.getAsync(this.options.buckets.users, userId).nodeify(cb);
};
this.options.buckets.usersは何者だ?
options = _.extend({
buckets: {
meta: 'meta',
parents: 'parents',
permissions: 'permissions',
resources: 'resources',
roles: 'roles',
users: 'users'
}
}, options);
this.options.buckets.users:usersテキストです.では、これらのパラメータ「acl」、「users」、「1024」を連想します.驚いたかどうか見てみましょう.意外です.
"acl_users@1024": {
"type": "set",
"value": [
"user"
]
}
簡単だよjsにはbucketKeyという方法があります.専門ユーザーが格納しているkeyをつなぎ合わせるので、どんなデータを手に入れたいのか、考え方は簡単です.
bucketKey : function(bucket, keys){
var self = this;
if(Array.isArray(keys)){
return keys.map(function(key){
return self.prefix+'_'+bucket+'@'+key;
});
}else{
return self.prefix+'_'+bucket+'@'+keys;
}
}
現在のすべてのロールを取得し、どのように取得するかは、主にスーパー管理者に与えられます.接合部aclだけでmeta@rolesを選択すると、すべてのキャラクタを取得できます.
/**
allRoles( userId)
Role
@param {String|Number} Id
**/
Acl.prototype.allRoles = function (userId) {
contract(arguments)
.params('string|number')
.end()
return userId ? this.userRoles(userId) :
this.backend.getAsync(this.options.buckets.meta, this.options.buckets.roles)
.then(roles => roles.filter(r => !!r))
}
これまで,データ構造を解析した後,多くのインタフェースが露出していないデータを得ることができた.私たちが最も関心を持っている問題に戻って、これは通マッチングをサポートしていません.どうすればいいですか??
/**
getMappedRerouces(path,resources)
@param {String|Number}
@param {Array} Resource
*/
function getMappedRerouces(path, resources) {
return [].concat(resources.filter(r = dbRe => {
//TODO:: option
let re = pathToRegexp(dbRe)
return !!re.exec(path)
}))
}
これは現在pathマッチングを要求しているすべてのResourceを取得することができ、複数である可能性が高いので、どのようにすれば、いずれのマッチングも可能であるはずです.最後のコードは
const Acl = require('acl')
const contract = require('../node_modules/[email protected]@acl/lib/contract')
const pathToRegexp = require('path-to-regexp')
const originalIsAllowed = Acl.prototype.isAllowed
/**
getMappedRerouces(path,resources)
@param {String|Number}
@param {Array} Resource
*/
function getMappedRerouces(path, resources) {
return [].concat(resources.filter(r = dbRe => {
//TODO:: option
let re = pathToRegexp(dbRe)
return !!re.exec(path)
}))
}
/**
getAllResources( userId)
@param {String|Number} Id
*/
Acl.prototype.allResources = function (userId) {
contract(arguments)
.params('string|number')
.end()
return userId ? this.userRoles(userId).then(roles => this.whatResources(roles)) : this._allResources()
}
Acl.prototype._allResources = function () {
return this.allRoles()
.then(roles => this.backend.unionAsync(this.options.buckets.resources, roles))
}
/**
allRoles( userId)
Role
@param {String|Number} Id
*/
Acl.prototype.allRoles = function (userId) {
contract(arguments)
.params('string|number')
.end()
return userId ? this.userRoles(userId) :
this.backend.getAsync(this.options.buckets.meta, this.options.buckets.roles)
.then(roles => roles.filter(r => !!r))
}
/**
isAllowed( userId, resource, permissions, function(err, allowed) )
Checks if the given user is allowed to access the resource for the given
permissions (note: it must fulfill all the permissions).
@param {String|Number} User id.
@param {String|Array} resource(s) to ask permissions for.
@param {String|Array} asked permissions.
@param {Function} Callback called wish the result.
*/
Acl.prototype.isAllowed = function (userId, resource, permissions, cb) {
contract(arguments)
.params('string|number', 'string', 'string|array', 'function')
.params('string|number', 'string', 'string|array')
.end();
let args = [...arguments]
// 1.userId => roles
// 2.roles => resources |
// 3. resources path, resources|resource
// 4. resource
return this.allResources(userId)
.then(dbRe => getMappedRerouces(resource, Object.keys(dbRe)))
.then(resources => {
// resource
return Promise.all((resources || []).map(re => {
return originalIsAllowed.apply(this, [args[0], re, ...args.slice(2)])
}))
}).then(allows => {
return allows.some(Boolean)
})
}
module.exports = Acl
どのように使うか、
acl.allow([
{
roles: 'user',
allows: [
{
resources: ['/msg', '/msg/:id', '/download', '/activities','/msg/(.*)'],
permissions: '*'
}
]
}
])
ミドルウェアブロック
const acl = require('../acl')
//const getAllRouter = require('./util/getAllRouter')
const pathToRegexp = require('path-to-regexp')
const loginPath = '/login'
module.exports = app => {
async function aclmd(req, res, next) {
var userId = 1024
if (userId) {
const path = req.path
if (path == loginPath) {
await next()
} else {
//const aa = await anyMatch(path, userId, acl)
const allowed = await acl.isAllowed(userId, path, '*')
if (allowed) {
next()
} else {
res.redirect(loginPath)
res.end();
}
}
} else {
res.redirect(loginPath)
res.end();
}
}
app.use(aclmd)
}
Node acl demonode権限制御モジュールnode_aclの応用