我正在尝试在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这解决了最后一块拼图。
答案 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以找出令牌,然后验证。