2017-05-28 97 views
1

我正在尝试在nodejs中构建一个简单的web令牌protected api。我一直在关注本教程authenticate a node js api with json web tokens,并一直在我的应用中实施这些步骤。我现在有一个允许我获取/发布/放置/删除的api运行,并为用户生成webtoken并以纯文本形式显示它(用于开发目的)。我正在使用节点restful api的,但我有一些麻烦理解如何实际验证客户端是否发送webtoken在他们的请求,允许这些get/post/put/delete请求之前。使用Json Web令牌的Node-Restful

这是我的路由器。在那里我定义允许的请求:

const express = require('express') 
const router = express.Router() 

// Models - Load models here 
var userModel = require('./models/User') 

// Controllers - Load controllers here 
const userController = require('./controllers/userController') 

// Routes - Define routes here 
router.post('api/authenticate', userController.authenticate) //Route that generates the webkey and shows it in the response 

// Configure the endpoint that node-restful will expose. Here I want to first check if the user is sending his or her api key. Before allowing these methods. 
userModel.methods(['get', 'put', 'post', 'delete']) 
userModel.register(router, '/api/users') 

// Export the router object 
module.exports = router 

这里是我的userController生成令牌。

// Dependencies 
const User = require('../models/User') 
const jwt = require('jsonwebtoken') 
const config = require('../config.js') 

module.exports = { 
    authenticate: function(req, res, next) { 
    // find the user 
    User.findOne({username: req.body.name}, function(err, user) { 

     if (err) throw err; 

     if (!user) { 
     res.json({ 
      success: false, 
      message: 'Authentication failed. User not found.' }); 

     } else if (user) { 
     // check if password matches 
     if (user.password != req.body.password) { 
      res.json({ 
      success: false, 
      message: 'Authentication failed. Wrong password.' }); 

     } else { 
      // if user is found and password is right 
      // create a token 
      var token = jwt.sign(user, config.secret, { 
      expiresIn: 60*60*24 // expires in 24 hours 
      }); 

      // return the information including token as JSON 
      res.json({ 
      success: true, 
      message: 'Enjoy your token!', 
      token: token 
      }); 
     } 
     } 
    }) 
    } 
} 

这里是我的用户模型。

// Dependencies 
const restful = require('node-restful') 
const mongoose = restful.mongoose 

// Schema 
const userSchema = new mongoose.Schema({ 
    username: String, 
    password: String, 
    email: String 
}) 

// Return the model as a restful model to allow it being used as a route. 
module.exports = restful.model('User', userSchema) 

是否有某种方式可以保护这些端点,使用与我目前使用的相同的语法来公开它们?我相信我会定义方法之前,请检查网络令牌:

userModel.methods(['get', 'put', 'post', 'delete']) 
userModel.register(router, '/api/users') 

如果我只是删除方法本身,用户将无法获得页面,并显示一个:“不能GET/api/users“错误。如果我想显示自定义错误怎么办?例如:“没有提供Web令牌,注册认证”等等?任何帮助深表感谢。先谢谢你。

我现在有一个函数可以在服务页面之前检查令牌。它似乎现在工作。目前,我在postman中手动传递令牌作为头文件:x-access-token。如何在生成时捕获令牌并自动让客户端在未来的请求中发送令牌?这是检查令牌和受保护路由的函数。

太好了。我在等待任何答案的同时继续工作,并完成了此步骤。我现在可以生成令牌并使用邮递员传递给我创建的安全路线。它的工作原理非常完美,但我很努力地理解我将如何在客户端保存令牌并在每个请求上传递该令牌。我仍然生成令牌,如上所述。我可以通过手动将它作为x-access-token传递给我的头部来验证令牌,但我该如何自动执行此操作?

更新

这里是检查利用该功能的令牌和一个受保护的路由功能:

//路线 - 这里定义路线

function getToken(req, res, next) { 

    var token = req.body.token || req.query.token || req.headers['x-access-token']; 

    // decode token 
    if (token) { 

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

    } else { 

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

    } 

} 

router.get('/entries', getToken, entryController.get) 

我发现这个问题save-token-in-local-storage-using-node解决了最后一块难题。

回答

1

你可以简单地为这种目的编写一个中间件。客户端通常会在标题中发送令牌,以便您可以获取标题信息并进行验证。你的中间件会是这样的。

module.exports = (req, res, next) => { 
 
    
 
\t if (!req.headers.authorization) { 
 
\t \t return res.status(401).json({ 
 
\t \t \t success: false, 
 
\t \t \t message: "You are not authorized for this operation." 
 
\t \t }) 
 
\t } 
 

 
\t // get the authorization header string 
 
\t const token = req.headers.authorization 
 

 
\t // decode the token using a secret key-phrase 
 
\t return jwt.verify(token, config.secret, (err, decoded) => { 
 
\t \t 
 
\t \t // the 401 code is for unauthorized status 
 
\t \t if (err) { 
 
     return res.status(401).json({ 
 
     success: false, 
 
     message: "You are not authorized for this operation." 
 
     }) 
 
    } 
 

 
\t \t const username = decoded.username 
 

 
\t \t // check if a user exists 
 
\t \t return User.findOne({username: username}, (userErr, user) => { 
 

 
\t \t \t if (userErr) { 
 
\t \t \t \t return res.status(500).json({ 
 
\t \t \t \t \t success: false, 
 
\t \t \t \t \t message: "Error occured while processing. Please try again.", 
 
\t \t \t \t \t err: userErr 
 
\t \t \t \t }) 
 
\t \t \t } 
 

 
\t \t \t if (!user) { 
 
\t \t \t \t return res.status(401).json({ 
 
\t \t \t \t \t success: false, 
 
\t \t \t \t \t message: "You are not authorized for this operation." 
 
\t \t \t \t }) 
 
\t \t \t } 
 
    
 
\t \t \t return next() 
 
\t \t }) 
 
\t }) 
 
}

为了安全起见,最好是存放在JWTs您与用户相关的应用程序。完整的解释可以在here找到。

更新: 您可以将令牌保存在cookie中,并解析cookie以找出令牌,然后验证该令牌。

+0

太好了。我在等待任何答案的同时继续工作,并完成了此步骤。我现在可以生成令牌并使用邮递员传递给我创建的安全路线。它的工作原理非常完美,但我很努力地理解我将如何在客户端保存令牌并在每个请求上传递该令牌。我仍然生成令牌,如上所述。我可以通过手动将它作为x-access-token传递给我的头部来验证令牌,但我该如何自动执行此操作?检查我的更新问题的代码。 – n0rd

+0

查看已更新的答案。 – Tolsee

+0

太棒了。我想知道这是否是我应该做的。所以我需要将这个标记保存为一个cookie,这应该不是我目前在我的令牌生成中使用的json响应。它是否正确? – n0rd