Node.js JSON Web Token 使用

翻譯原文連接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

構建一個簡單的server.js

在下面的代碼中,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);
複製代碼

建立一個簡單User

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 });
  });
});
複製代碼

展現咱們的User

如今咱們建立咱們的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

受權並建立一個Token

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在數據庫進行有期限的保存。

使用中間件來保護私有API

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);
複製代碼

node-jwt

相關文章
相關標籤/搜索