翻译原文连接javascript
受权认证是每个应用最重要的组成部分,众所周知互联网在安全问题方面始终处于挑战和进化的过程当中。在过去咱们一般会使用Passport这样的npm 包来解决验证问题,尽管使用基于认证受权的session会话能够解决普通的web app开发问题,可是对于不少跨设备、跨服务的API和扩展web services方面,session会话则显然捉襟见肘。java
本文的目标在于快速构建一套基于Node express的API,而后咱们经过POST MAN来最终跑通这个API。整个故事其实很简单,路由分为unprotected 和 protected 两类routes。在经过密码和用户名验证以后,用户会获取到token而后保存在客户端,在以后的每次请求调用的时候都会带着这个token。node
node和postman已经安装完毕git
在下面的代码中,github
// =======================
// get the packages we need ============
// =======================
var express = require('express');
var app = express();
var bodyParser = require('body-parser');
var morgan = require('morgan');
var mongoose = require('mongoose');
var jwt = require('jsonwebtoken'); // used to create, sign, and verify tokens
var config = require('./config'); // get our config file
var User = require('./app/models/user'); // get our mongoose model
// =======================
// configuration =========
// =======================
var port = process.env.PORT || 8080; // used to create, sign, and verify tokens
mongoose.connect(config.database); // connect to database
app.set('superSecret', config.secret); // secret variable
// use body parser so we can get info from POST and/or URL parameters
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
// use morgan to log requests to the console
app.use(morgan('dev'));
// =======================
// routes ================
// =======================
// basic route
app.get('/', function(req, res) {
res.send('Hello! The API is at http://localhost:' + port + '/api');
});
// API ROUTES -------------------
// we'll get to these in a second
// =======================
// start the server ======
// =======================
app.listen(port);
console.log('Magic happens at http://localhost:' + port);
复制代码
app.get('/setup', function(req, res) {
// create a sample user
var nick = new User({
name: 'Nick Cerminara',
password: 'password',
admin: true
});
// save the sample user
nick.save(function(err) {
if (err) throw err;
console.log('User saved successfully');
res.json({ success: true });
});
});
复制代码
如今咱们建立咱们的API routes以及以JSON格式返回全部的users. 咱们将使用Expres自带的Router()方法实例化一个apiRoutes
对象,来处理相关请求。web
// API ROUTES -------------------
// get an instance of the router for api routes
var apiRoutes = express.Router();
// TODO: route to authenticate a user (POST http://localhost:8080/api/authenticate)
// TODO: route middleware to verify a token
// route to show a random message (GET http://localhost:8080/api/)
apiRoutes.get('/', function(req, res) {
res.json({ message: 'Welcome to the coolest API on earth!' });
});
// route to return all users (GET http://localhost:8080/api/users)
apiRoutes.get('/users', function(req, res) {
User.find({}, function(err, users) {
res.json(users);
});
});
// apply the routes to our application with the prefix /api
app.use('/api', apiRoutes);
复制代码
咱们可使用POSTman来对路由进行测试。数据库
测试: http://localhost:8080/api/ ,看看能不能看到相关message内容express
测试: http://localhost:8080/api/users ,检查是否有用户列表数据返回npm
在http://localhost:8080/api/authenticate
中登陆用户名和密码,若成功则返回一个token.json
以后用户应将该token存储客户端的某处,好比localstorage. 而后在每一次请求时带着这个token,在调用相关protected routes的时候,该router应该经过Middleware来检查token的合法性。
var apiRoutes = express.Router();
// (POST http://localhost:8080/api/authenticate)
apiRoutes.post('/authenticate', function(req, res) {
User.findOne({
name: 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) {
if (user.password != req.body.password) {
res.json({ success: false, message: 'Authentication failed. Wrong password.' });
} else {
const payload = {
admin: user.admin
};
// 若是对于客户的要求不是很高就自定义一个token, 若是对于token有时间限制则使用jwt 插件进行生成。
var token = jwt.sign(payload, app.get('superSecret'), {
expiresInMinutes: 1440 // expires in 24 hours
});
// 将登录成功后的信息携带token返回给客户端
res.json({
success: true,
message: 'Enjoy your token!',
token: token
});
}
}
});
});
...
复制代码
在上面的代码中,咱们使用了jsonwebtoken
包建立生成了token,并经过mongoDB的相关包将token在数据库进行有期限的保存。
var apiRoutes = express.Router();
// 当客户端调用/api路由也就apiRoutes实例化的时候,首先会被拦截进行token检查。
apiRoutes.use(function(req, res, next) {
// 从不一样的地方尝试读取token
var token = req.body.token || req.query.token || req.headers['x-access-token'];
// decode token
if (token) {
// 验证token
jwt.verify(token, app.get('superSecret'), function(err, decoded) { if (err) {
return res.json({ success: false, message: 'Failed to authenticate token.' }); } else {
//若是一切顺利进入路由逻辑环节
req.decoded = decoded;
next();
}
});
} else {
//若是检查没有经过则返回403
return res.status(403).send({
success: false,
message: 'No token provided.'
});
}
});
// route to show a random message (GET http://localhost:8080/api/)
...
// route to return all users (GET http://localhost:8080/api/users)
...
// apply the routes to our application with the prefix /api
app.use('/api', apiRoutes);
复制代码