【问题标题】:How to setup an authentication middleware in Express.js如何在 Express.js 中设置身份验证中间件
【发布时间】:2021-08-30 00:51:39
【问题描述】:

我设置了一个 Web 应用程序,其中包含一些需要登录的内部页面。我使用 Node 和 Express.js 来设置服务器并控制路由和身份验证工作正常。

我在question related to the same application 中提出了@zanko 建议,以避免在每个页面的路径中复制身份验证代码,就像现在一样。

目前我的 app.js 看起来是这样的(以下是节选):

var session = require('express-session');
//use sessions for tracking logins
app.use(session({
  secret: 'mercuia',
  resave: true,
  saveUninitialized: false,
  store: new MongoStore({
  mongooseConnection: db
})
}));

// serve static files from template
app.use(express.static(__dirname + '/public'));

// include routes
var routes = require('./routes/router');
app.use('/', routes);

// catch 404 and forward to error handler
app.use(function (req, res, next) {
  var err = new Error('File Not Found');
  err.status = 404;
  next(err);
});

// error handler
// define as the last app.use callback
app.use(function (err, req, res, next) {
  res.status(err.status || 500);
  res.send(err.message);
});

我的身份验证方法(在 routes.js 中)看起来像这样(在示例中,用于路由 /clientPage):

// GET route after registering
router.get('/clientPage', function (req, res, next) {
  User.findById(req.session.userId)
    .exec(function (error, user) {
      if (error) {
        return next(error);
      } else {      
        if (user === null) {     
          var err = new Error('Not authorized! Go back!');
          err.status = 400;
          return next(err);
        } else {
          return res.sendFile(path.join(__dirname + '/../views/clientPage.html'));
        }
      }
    });
});

我怎样才能编写一个身份验证中间件(使用相同的逻辑)并为所有且仅需要的路由调用它?

【问题讨论】:

  • 我想知道你是如何填充你的req.session.userId 我在app.js 中看不到任何这样做的中间件

标签: node.js express authentication


【解决方案1】:

您可以创建一个名为auth.js 的新模块,然后使用它来检查用户是否被授权:

auth.js

module.exports.isAuthorized  = function(req, res, next) {

    User.findById(req.session.userId).exec(function (error, user) {
        if (error) {
            return next(error);
        } else {      
            if (user === null) {     
                var err = new Error('Not authorized! Go back!');
                err.status = 401;
                return next(err);
            } else {
                return next();
            }
        }
    });
}

routes.js

var auth = require('./auth');

// GET route after registering
router.get('/clientPage', auth.isAuthorized, function (req, res, next) {
    res.sendFile(path.join(__dirname + '/../views/clientPage.html'));
});

【讨论】:

  • 你的require('auth');应该是相对的部分吗?这将在node_modules 文件夹内查看
  • 我只是给了他处理问题的想法,也在你的回答中app.use(restrictMiddleware);将限制中间件应用于所有路由,
  • 是的,它将适用于 app.use(restrictMiddleware) 下的所有路由,但在此之前不适用。你的更灵活,但可能需要根据他想要限制多少条路线将它放在很多路线上
  • 我同意,但是您可以将函数提升到中间件之前的路由中。就我个人而言,我更喜欢将它们分开(对我来说更好的思维模式),因为我们可以清楚地将未经授权的路线与授权路线分开,而不是将它们混合在一起。但它是 OP 必须做出的设计决策,没有任何解决方案的灵丹妙药。
  • 真的很喜欢这个答案。我会将 err.status 更改为 401,因为这是一个授权问题。
【解决方案2】:

创建一个模块(导出函数的文件,在本例中为中间件函数)。中间件函数具有以下签名function (req, res, next) { .... }

restrict.js

module.exports = function (req, res, next) {
  User.findById(req.session.userId)
    .exec(function (error, user) {
      if (error) {
        return next(error);
      } else {
        if (user === null) {
          const err = new Error("Not authorized! Go back!");
          err.status = 400;
          return next(err); // This will be caught by error handler
        } else {
          return next(); // No error proceed to next middleware
        }
      }
    });
};

app.js

// serve static files from template
app.use(express.static(__dirname + '/public'));

// include routes
const routes = require('./routes/router');

//If you have a more granular route you can split it 
const someOtherRoute = require('./routes/someotherRoute');

const restrictMiddleware = require("./restrict");

app.use("/", someOtherRoute); // this route will not be check for authorization
app.use(restrictMiddleware);
app.use('/', routes);

// catch 404 and forward to error handler
app.use(function (req, res, next) {
  const err = new Error('File Not Found');
  err.status = 404;
  next(err);
});

// error handler
// define as the last app.use callback
app.use(function (err, req, res, next) {
  res.status(err.status || 500);
  res.send(err.message);
});

如果您的环境支持,我会使用constlet。它的 2017 年 :)

【讨论】:

  • 如果您希望有选择地授权每条路线,您也可以使用@YouneL 回答。
  • 我一定会试一试的
猜你喜欢
  • 1970-01-01
  • 2021-01-20
  • 2015-07-20
  • 2019-06-28
  • 2020-02-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-15
相关资源
最近更新 更多