代码之家  ›  专栏  ›  技术社区  ›  AleDG

JWT中使用承载方案的认证报头

  •  0
  • AleDG  · 技术社区  · 7 年前

    我正在使用Express、Passport和jsonwebtoken为NodeJS中的网站构建身份验证系统。 我到处都找了,但找不到解决问题的方法。

    现在我有一个身份验证控制器:

    module.exports = function() {  
    var strategy = new BearerStrategy(params, function(payload, done) {
        var decodedToken = jwtDecode(payload)
        db.default.Account.find({where: {id: decodedToken.id}}).then(account =>{
            if (account) {
                return done(null, {
                    id: account.id,
                    role: account.role
                })
            } else {
                return done(new Error("User not found"), null)
            }
        })
    })
    
    passport.use(strategy)
    return {
        initialize: function() {
            return passport.initialize()
        },
        authenticate: function() {
            return passport.authenticate("bearer", cfg.jwtSession)
        }
       }
    }
    

    在其中,我使用了BearerStrategy,这段代码很有效,因为我的/登录路径为用户包装了一个令牌并返回该令牌

      accountController.post("/login", function(req, res) {
         if (req.body.email && req.body.password) {
         var accEmail = req.body.email
         var accPassword = req.body.password
         db.default.Account.find({where: {email: accEmail, password: 
           accPassword}}).then(account =>{
         if (account) {
            var payload = {
               id: account.id,
               role: account.role
          }
          var token = jwt.sign(payload, cfg.jwtSecret)
          console.log(token)
          res.status(200).json({
              token: 'Bearer ' + token
          })
           } else {
             res.sendStatus(401)
         }
       })
     } else {
         res.sendStatus(401)
       }
    })
    

    如果我使用Postman发送HTTP请求,尝试访问路由/帐户,并将令牌设置为标头,则一切正常。

    accountController.get('/account', auth.authenticate('bearer', { session: false }), function(req, res){
    res.status(200).render('pages/homepage')
    })
    

    我无法回答的问题是: 用res.json({token:token})发回令牌是不够的,令牌需要存储在某个地方,对吗?我应该如何使用RestAPI存储令牌,此外,我应该如何在每个请求中从HTTP标头内的客户端发送令牌?

    我愿意听取关于如何在存储和发送JWT之间建立这种联系的建议(因为JWT工作的生成和验证) 非常感谢。

    1 回复  |  直到 7 年前
        1
  •  2
  •   Mika Sundland    7 年前

    是的,这样发送令牌就足够了。您只需确保客户端以某种方式收到令牌。在您的特定情况下,客户端将向 /login 端点,并从请求的响应中读取令牌。在半伪代码(客户端Javascript)中:

    http.post('/login', (response) => {
      let token = response.split(' ')[1];
    });
    

    客户端存储令牌。它存储在 localStorage , sessionStorage 或者放在饼干里。有 pros and cons 适用于各种存储场所。必须对客户端进行编程,将其存储在其中一个位置,而服务器根本不存储它。如果您使用的是Angular或React等前端框架,您可以使用Google和“Angular、jwt、Storage”等搜索词找到大量信息和示例。如果您使用的是vanilla JS,您可以按照提供的链接中的示例进行操作。基于上述半伪代码:

    http.post('/login', (response) => {
      let token = response.split(' ')[1];
      localStorage.setItem('token', token);
    });
    

    令牌与HTTP标头中的每个请求一起发送,HTTP标头名为 批准 . 标题应具有以下格式

    Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
    

    ey。。。stuff是实际的令牌。在您的情况下,您可能需要使用 持票人 (非资本化 b ),因为你已经设置了Passport,这样就可以了。你也可以做到 auth.authenticate('Bearer', ... 在您的代码中,使其更“正确”。在以前的文档和博客帖子中,你经常可以看到 JWT公司 而不是 持票人 ,但这并没有真正遵循事实上的标准。

    如果您以这种方式发送,Passport应该正确读取令牌。

    如何添加 批准 客户端中的标题取决于您是否使用框架,以及客户端是否为浏览器。如果你使用的是vanilla JS,你可以阅读 this 链接如果你使用的是一个框架,你可以在谷歌上“设置授权头,角度”或类似的东西。通常在官方文件和博客帖子中都有大量信息。代码中添加 批准 字段通常称为 身份验证拦截器 如果您使用的是前端框架。拦截器有点像中间件。

    最后,您要写以下内容:

    我应该如何使用RestAPI存储令牌。。。

    REST并不真正关心令牌的存储方式。这是在客户端完成的,与REST无关。然而,REST关心端点的名称。是 /登录 如果它是动词,真的是正确的名字吗?问题被提出并回答 here .