【问题标题】:JWT UnauthorizedError: No authorization token was found (GET request with cookie)JWT UnauthorizedError:未找到授权令牌(带有 cookie 的 GET 请求)
【发布时间】:2017-06-12 19:16:12
【问题描述】:

我有一个奇怪的问题,或者我不明白 JWT 在 Express 上下文中是如何工作的。

var express = require('express')
var app = express();
var expressJWT = require('express-jwt');
var jwt = require('jsonwebtoken');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var unless = require('express-unless');


app.set('secret', 'some secret');

app.use(cookieParser());
app.use(bodyParser.urlencoded({ extended: false }));
app.use("/", expressJWT({secret:app.get('secret')})
  .unless({
    path:[
      '/',
      '/foo',
      '/login'
    ]}
  ));


  // my custom route middleware to verify a token
app.use(function(req, res, next) {
  console.log("------------------------------------");
  console.log("route middleware to verify a token");
  console.log("");
  // check header or url parameters or post parameters for token
  var token = req.body.access_token || req.query.access_token || req.headers['x-access-token'] || req.cookies.access_token;
  console.log("req.cookies.access_token:", req.cookies.access_token);
  console.log("token:", token);
  // decode token
  if (token) {

    // verifies secret and checks exp
    jwt.verify(token, app.get('secret'), function(err, decoded) {
      if (err) {
        console.log("jwt.verify ERROR")
        return res.json({ success: false, message: 'Failed to authenticate token.', err:err });
      } else {
        console.log("jwt.verify OK")
        // if everything is good, save to request for use in other routes
        req.decoded = decoded;
        next();
      }
    });

  } else {

    // if there is no token
    // return an error
    return res.status(403).send({
        success: false,
        message: 'No token provided.'
    });

  }
});


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

  res.send('Hello World!. /foo is open, /bar is protected. Login at /login')
})

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

  res.send('Foo')
})

app.get('/bar', function (req, res) {
  res.send('Foo')
})

app.get('/login', function (req, res) {
  var username = 'mock_username';
  var myToken = jwt.sign({username:username}, app.get('secret'));
  res.cookie('access_token', myToken).send("logged in, check cookie");
})


app.listen(3000, function () {
  console.log('Example app listening on port 3000!')
})

我正在设置 JWT 令牌并将其保存到 /login 路由中的 cookie。 如果我在浏览器中检查 cookie(Chrome 中的开发工具),这将起作用并且设置了令牌。

  • 我访问了 / 或 /foo 路由(不受除非指定的保护),浏览器显示正确的结果,但控制台仍然抛出 UnauthorizedError。如果我用“除非”明确地将其标记为不受保护的路由,为什么控制台会显示错误?

  • 我访问了 /bar 路由(受保护),我的中间件没有被调用,我在控制台和浏览器中都收到了 UnauthorizedError。如何确保在此处触发中间件,如果确实在我的中间件中找到并验证了令牌,我如何提供对该路由的访问权限?

【问题讨论】:

  • 因为你还没有将unless附加到其他中间件。
  • 哪些,全部?这是两个问题中第一个问题的答案。请以答案的形式提出,以便我投票并给你积分:)

标签: node.js express cookies jwt


【解决方案1】:

我访问了 / 或 /foo 路由(unprotected as specified with unless),浏览器显示正确的结果,但控制台仍然抛出 UnauthorizedError。如果我用“除非”明确地将其标记为不受保护的路由,为什么控制台会显示错误?

通过指定unless,您使//foo 路由仅不受app.use("/", expressJWT(...) 的保护,而不受后续middlewares 的保护。该请求也将传递给您的自定义中间件。

我访问 /bar 路由(受保护),我的中间件没有被调用,我在控制台和浏览器中都收到 UnauthorizedError。如何确保中间件确实在此处触发,如果确实在我的中间件中找到并验证了令牌,我如何提供对该路由的访问权限?

因为,应用程序在app.use("/", expressJWT(...)) 处崩溃,当时它找不到authorization token。因此,它无法访问您的自定义中间件。

可能的解决方案:1

由于您的情况JWT令牌存储在cookie中,您可以设置getToken方法获取令牌并让express-jwt验证它,并完全删除您的自定义中间件。

例如

app.use("/", expressJWT({
  secret : app.get('secret'),
  getToken: function fromCookie (req) {
    var token = req.cookies.access_token || req.body.access_token || req.query.access_token || req.headers['x-access-token'] ;
    if (token) {
      return token;
    } 
    return null;
  }
}).unless({
    path:[
      '/',
      '/foo',
      '/login'
    ]}
));

并处理错误

app.use(function (err, req, res, next) {
  if (err.name === 'UnauthorizedError') {
    return res.status(403).send({
      success: false,
      message: 'No token provided.'
    });
  }
});

可能的解决方案:2

您可以通过实现自定义中间件(您已经完成)来进行自定义jwt 验证。那么就完全不需要下面的中间件了。

删除以下行。

app.use("/", expressJWT({secret:app.get('secret')}).unless(...)

为了保护和取消保护路由,请将unprotected 路由放在自定义中间件之前,将protected 路由放在自定义中间件之后(天真的方式)。

希望对你有帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-09-21
    • 2019-12-11
    • 2015-11-27
    • 1970-01-01
    • 2020-07-27
    • 2020-02-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多