パラメータを受け入れるexpressjsミドルウェアの作成


104

パラメータを受け入れることができるミドルウェアを作成しようとしています。これはどのように行うことができますか?

app.get('/hasToBeAdmin', HasRole('Admin'), function(req,res){

})

HasRole = function(role, req, res, next){
   if(role != user.role){
      res.redirect('/NotInRole);
   }

   next();
}

41
ハ、あなたは私の正確なシナリオについて私の正確な質問をしましたが、6年前です。SOは素晴らしいです。
aero

6
D:私が探していた@aeroまったく同じこと
Jesonディアス

4
@aero 7年後私はまったく同じものを探しています:D
jean d'arme19年

4
@aero 7年以上後、まったく同じものを探しています!
SIDD

4
@aero 8〜年後、まったく同じものを探しています!\ O /
イタロ・スーザ

回答:


162
function HasRole(role) {
  return function(req, res, next) {
    if (role !== req.user.role) res.redirect(...);
    else next();
  }
}

また、同じ関数の複数のコピーを作成しないようにしたいです。

function HasRole(role) {
  return HasRole[role] || (HasRole[role] = function(req, res, next) {
    if (role !== req.user.role) res.redirect(...);
    else next();
  })
}

9
2番目の方法では、パラメーターをキャッシュしますが、これは望ましい動作である場合とそうでない場合があります。
Pier-Luc Gendreau 2014

1
@Jonathan Ong、関数の2番目の定義について説明してください。そこで何が起こっているのですか?次の行がわかりませんreturnHasRole [role] || (HasRole [role] = function(req、res、next){
RafayHassan19年

1
@JonathanOngノードをそれほどよく知らない人のために、2番目の例をもう少し説明していただけますか?(私を含む)。同じ関数の複数のコピーをいつ取得でき、これが問題を引き起こす可能性があるのはいつですか?ありがとう。
デイブ

キャッシングなし、app.get('/a', hasRole('admin'))およびapp.get('/b', hasRole('admin'))ごとに新しいクロージャを作成しますhasRole。非常に大きなアプリケーションがない限り、これは現実的にはそれほど重要ではありません。私はデフォルトでこのようにコーディングします。
JonathanOng19年

14
app.get('/hasToBeAdmin', (req, res, next) => {
  hasRole(req, res, next, 'admin');
}, (req,res) => { 
    // regular route 
});

const hasRole = (req, res, next, role) => {
   if(role != user.role){
      res.redirect('/NotInRole');
   }
   next();
};

良いシンプルなアイデア。ミドルウェアは実際には通常の機能です。他の値を渡してみませんか。最初の関数にreq、res、nextを含めてください。
zevero 2016年

1
多くの場合、コードはそれ自体を物語っていますが、コードに説明を追加することをお勧めします。これは、コードのみの回答が傾向があるため、レビューキューに表示されます。
ウィル

SOに行く前からそのアプローチを考えていたのですが、「まぁ、きっともっといい方法がある」と思いました。訪問した後、これが本当に最も簡単で最も効果的な方法であることがわかりました。
Fusseldieb

3

または、ケースが多すぎない場合、またはロールが文字列でない場合:

function HasRole(role) {
  return function (req, res, next) {
    if (role !== req.user.role) res.redirect(/* ... */);
    else next();
  }
}

var middlware_hasRoleAdmin = HasRole('admin'); // define router only once

app.get('/hasToBeAdmin', middlware_hasRoleAdmin, function (req, res) {

})

エレガントなソリューション
Leos Literak

2

さまざまなアクセス許可レベルがある場合は、次のように構成できます。

const LEVELS = Object.freeze({
  basic: 1,
  pro: 2,
  admin: 3
});

/**
 *  Check if user has the required permission level
 */
module.exports = (role) => {
  return (req, res, next) => {
    if (LEVELS[req.user.role] < LEVELS[role]) return res.status(401).end();
    return next();
  }
}

0

私はこのソリューションを使用します。body reqでjwtトークンを受け取り、そこから役割情報を取得します

//roleMiddleware.js

const checkRole = role => {
    
    return (req, res, next) => {
        if (req.role == role) {
            console.log(`${role} role granted`)
            next()
        } else {
            res.status(401).send({ result: 'error', message: `No ${role} permission granted` })
        }
    }
}

module.exports = { checkRole }

したがって、最初に認証ミドルウェアを使用してが有効なユーザーであるかどうかを確認し、次にロールミドルウェアを使用してユーザーがAPIルートにアクセスできるかどうかを確認します

// router.js

router.post('/v1/something-protected', requireAuth, checkRole('commercial'), (req, res) => {
    // do what you want...
})

役に立つことを願っています

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.