【问题标题】:Authentication in Express MiddlewareExpress 中间件中的身份验证
【发布时间】:2017-10-14 20:26:26
【问题描述】:

我对此有点陌生。我有用 Node.js 和 Express.js 制作的 REST API。某些路由具有身份验证中间件。要使用这些路由,必须使用经过验证的用户身份验证令牌设置标头。我一直在使用本地存储的静态站点没有问题。我现在正在创建我的第一个动态站点(使用 Express),对于某些路由,我有中间件来加载显示页面所需的所有数据。在没有本地存储帮助的情况下,如何访问和使用身份验证令牌?

编辑(澄清): 所以这是我从数据库(mongoDB)中获取所有事务的 api 路由之一。

app.get('/transactions', authenticate, (req, res) => {
  Transaction.find().then((transaction) => {
    res.send({transaction});
  }, (e) => {
    res.status(400).send();
  });
});

这是运行的身份验证中间件。

var authenticate = (req, res, next) => {
    var token = req.header('x-auth');

    User.findByToken(token).then((user) => {
        if (!user) {
          return Promise.reject();
        }
        req.user = user;
        req.token = token;
        next();
    }).catch((e) => {
        res.status(401).send();
    });
};

现在在我的 express 网络服务器上,我有一条以下路线,我使用 getTransactions 来获取我的所有数据。 (我用车把显示)

router.get('/orders', getTransactions, (req, res) => {
  res.render('orders.hbs', {
    transaction: req.transactions.data.transaction
  });
});

这是中间件

var getTransactions = (req, res, next) => {
  axios.get('https://serene-wave-28270.herokuapp.com/transactions')
    .then((response) => {
      req.transactions = response;
      console.log(req.transactions.data.transaction);
      next();
    }).catch((e) => {
      console.log(e);
    })
}

因此,当我只是在不使用 express 作为网络服务器的情况下创建静态站点时,我只需让用户登录并将身份验证令牌保存在本地存储中。另外,我应该注意前两个块来自我的 api,底部两个来自 webserver,它们都单独托管在 Heroku 上。我不确定这是否是标准设计,所以我想我应该提一下。

【问题讨论】:

    标签: node.js rest express authentication


    【解决方案1】:

    您的问题并没有详细说明您正在尝试做什么,但我可以在 Express 中解释您可以使用的一般概念:

    Express 的常用方案是首先对用户进行身份验证,然后设置一个会话 cookie,表明用户已通过身份验证。由于 cookie 由浏览器自动存储,然后在每次请求时自动从浏览器发送到服务器,因此您将拥有该 cookie,服务器可以使用该 cookie 来识别服务器端会话,然后您可以使用任何您想要的信息在为该用户创建页面或响应 API 请求时从会话(用户标识或您存储在会话对象中的其他状态)获取。

    NPM 模块express-session 会为您处理大部分工作,因为它会自动创建会话对象、会话 cookie 并在每次请求时将两者挂钩。


    另一方面,如果您在客户端中已经有一个身份验证令牌,并且您只是希望在每次请求时自动将其传达给服务器,那么您可以将该身份验证令牌放入一个 cookie 并让服务器在每个请求的 cookie 中查找它。您甚至可以通过将 cookie 设置为 HttpOnly 使其更加安全,这样就无法从客户端 Javascript 访问身份验证令牌(这不会影响服务器访问它的能力)。

    【讨论】:

    • 感谢您的回复,我认为 express-session 可能是我需要的。很抱歉如此含糊,如果这会改变您的答案,我已经添加了一些代码!
    • @S_Farsai - 如果您想继续使用新代码显示的身份验证令牌,那么您可以将其从标头移动到 cookie,然后它将自动包含在来自该的所有请求中此域的客户端。这将使您不必使用本地存储,并将自动获取包含在所有请求中的令牌。
    • 太棒了,我很感激!我给了绿色检查
    【解决方案2】:

    您的问题没有太多细节,但这里有一些想法。

    您可以使用 cookie(如下面的 @jfriend00 详述)或使用请求的标头来检查有效的授权令牌(我将在下面描述)

    在 Express 中,您可以通过 req.headers 访问标头,因此您只需编写一个中间件,您将在当前中间件加载所有数据之前调用该中间件,以确保用户有权继续(调用next() 来调用下一个中间件)或使用自定义错误类型来标记身份验证错误,如果他不是(调用next(err) 跳过所有其他中间件并跳转到您的错误中间件)

    例如(假设您在某处定义了一个名为 AuthorizationError 的错误子类):

    const express = require('express');
    const AuthorizaztionError = require('<some path>');
    const app = express();
    
    function checkAuthTokenMiddleware(req, res, next) {
        if (req.headers && req.headers.authorization) {
            let token;
            const parts = req.headers.authorization.split(' ');
            if (parts.length == 2) {
                const [scheme, credentials] = parts;
    
                if (/^Bearer$/i.test(scheme)) { // or any other scheme you are using
                    token = credentials;
                }
    
                if (token === undefined) {
                    // access token - missing
                    return next(new AuthorizationError(
                        "Invalid access token.", // error_description
                        "invalid_token" // error
                    ));
                }
                // add something here to ensure the token is valid
                return next();
            }
        } else {
            // No authorization header => invalid credentials
            return next(new AuthorizationError(
                "Authorization header required.", // error_description
                "invalid_request" // error
            ));
        }
    
    }
    
    // Add this in your route declaration
    app.use(
        "/auth/test",
        checkAuthTokenMiddleware,
        function(req, res, next) {
            // do something
        }
    );
    
    // this must come last
    app.use(function errorMiddleware(err, req, res, next) {
        // return something
        if (err instanceof AuthenticationError) {
            // do something for example
            res.status(401).send(err.error_description);
        } else {
            // generic error handling, for example
            res.status(500).send("Error "+err);
        }
    })
    
    // ... 
    

    【讨论】:

    • 嗨,鲍里斯,感谢您的回答。抱歉这么含糊。我添加了一些代码进行澄清以防万一
    猜你喜欢
    • 2018-02-06
    • 1970-01-01
    • 2017-05-18
    • 2017-06-14
    • 1970-01-01
    • 2019-03-15
    • 1970-01-01
    • 2018-01-26
    • 2017-12-09
    相关资源
    最近更新 更多