Node-Restful with Json web tokens

时间:2017-05-28 11:27:46

标签: node.js express

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

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

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)

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

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

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

我现在有一个在提供页面之前检查令牌的功能。它现在似乎有效。目前我在邮递员中手动传递令牌作为标头:x-access-token。如何在生成时捕获令牌并自动使客户端在将来的请求中发送它?以下是检查令牌和受保护路由的函数。

大。我在等待任何答案的同时继续工作并完成了这一步。我现在可以生成令牌并使用postman传递给我创建的安全路由。它工作得很好,但我很想知道如何在客户端保存令牌并在每个请求上传递它。我仍然生成令牌,方法与上面相同。我可以通过手动将其作为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 个答案:

答案 0 :(得分:1)

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



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

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

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

		const username = decoded.username

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

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

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




出于安全原因,最好将JWT存储在与用户关联的应用程序中。完整的解释可以找到here

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