NODE + JWT + Mongo(簡單實現許可權管理)

廣州蘆葦科技Java開發團隊發表於2018-12-19

JWT簡介

  • 官方是這樣介紹的:

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.(JSON Web Token(JWT)是一個開放標準(RFC 7519),它定義了一種緊湊且獨立的方式,可以在各方之間作為JSON物件安全地傳輸資訊。 此資訊可以通過數字簽名進行驗證和信任。 JWT可以使用祕密(使用HMAC演算法)或使用RSA或ECDSA的公鑰/私鑰對進行簽名。)

  • 用途

    授權和安全傳輸資訊

  • token的結構 Header.Payload.Signature

    • Header 通常由兩部分組成:令牌的型別,即JWT,以及正在使用的雜湊演算法,例如HMAC SHA256或RSA。
    • Payload 加密的資料
    • Signature 簽名

應用

知道了JWT的用途後,我們就開始針對授權來結合node做簡單的實現。

  • 版本號

    • cnpm@6.0.0
    • npm@6.4.1
    • node@11.1.0
  • 流程

    流程圖

    • 使用者還沒登入時,只能訪問首頁、註冊、登入介面,如下圖

      首頁

      註冊

      登入

    • 登入過後能獲取自己的資訊

      獲取自己資訊

    • 如果沒輸入token,則提示沒有找到token,當然可以重定位到首頁

      沒有找到token

    • 輸入錯誤的token,提示使用者未登入

      使用者未登入

  • 目錄結構

目錄結構

說明:config.js為全域性配置檔案,user.js為Mongo資料庫對應的user實體,index.js為專案入口檔案。

  • config.js

    	module.exports = {
    		'network' : {
    			'port':8080
    		},
    		'salt': '0vAXJ@2R%PAxL9*Y#vLc8VQuLGk0BzdD',	
    		'jwtsecret': 'myjwttest',
    		'database': 'mongodb://127.0.0.1:27017/test'
    	};
    
    複製程式碼
  • user.js

    	var mongoose = require('mongoose');
    	var Schema = mongoose.Schema;
    
    	// 返回一個mongo使用者庫例項
    	module.exports = mongoose.model('User', new Schema({ 
    		name: String, 
    		password: String
    	}));
    
    複製程式碼
  • index.js

    	const express = require('express');
    	const app = express();
    
    	const crypto = require('crypto');
    	const util = require('util');
    
    	const bodyParser = require('body-parser');//request.body起效果而用
    	const mongoose = require('mongoose');//MongoDB
    	const jwt = require('jsonwebtoken'); // 使用jwt簽名
    	const config = require('./config'); // 引入配置
    	const User = require('./user'); // 引入mongo使用者庫例項
    
    	// 連線mongo
    	mongoose.connect(config.database);
    	// 設定加密祕鑰
    	app.set('superSecret', config.jwtsecret);
    	//設定request.body有效
    	app.use(bodyParser.urlencoded({ extended: false }));
    	app.use(bodyParser.json());
    
    	app.listen(config.network.port);
    
    	// 首頁
    	app.get('/', function (req, res) {
    	  res.send('這裡是首頁http://127.0.0.1:' + config.network.port + "/api");
    	});
    
    	// 註冊
    	app.post('/register', async function (req, res) {
    	  if (req.body.name && req.body.password) {
    
    		const salt = config.salt;
    		  const pwdEnc = await util.promisify(crypto.pbkdf2)(req.body.password, salt.toString('base64'), 10000, 64, 'sha256');
    
    		var user = new User({
    		  name: req.body.name,
    		  password: pwdEnc
    		});
    		user.save(function (err) {
    		  if (err) throw err;
    		  console.log('註冊成功');
    		  res.json({ success: true });
    		});
    	  } else {
    		res.json({ success: false, msg: "錯誤引數" });
    	  }
    	});
    
    	// 登入,登入成功返回JWT的Token 驗證使用者名稱密碼
    	app.post('/login', function (req, res) {
    	  User.findOne({
    		name: req.body.name
    	  }, async function (err, user) {
    		if (err) throw err;
    		if (!user) {
    		  res.json({ success: false, message: '未找到授權使用者' });
    		} else if (user) {
    		  const salt = config.salt;
    		  const pwdEnc = await util.promisify(crypto.pbkdf2)(req.body.password, salt.toString('base64'), 10000, 64, 'sha256');
    
    		  if (user.password != pwdEnc) {
    			res.json({ success: false, message: '使用者密碼錯誤' });
    		  } else {
    
    			var token = await util.promisify(jwt.sign)({
    			  user: user,
    			}, app.get('superSecret'), {
    			  expiresIn: '4h',
    			});
    			res.json({
    			  success: true,
    			  message: '請使用您的授權碼',
    			  token: token
    			});
    		  }
    		}
    	  });
    	});
    
    	//  建立需要授權的介面
    	var apiRoutes = express.Router();
    
    	//校驗機制
    	apiRoutes.use(async function (req, res, next) {
    
    	  // 獲取傳過來的token
    	  var token = req.headers['x-access-token'];
    
    	  if (token) {
    		// 解碼token獲取使用者資訊 decoded為加密前的內容
    		util.promisify(jwt.verify)(token, app.get('superSecret')).then(function(data){
    		  req.decoded = data;
    		  next(); //繼續下一步路由
    		}).catch((error)=>{
    		  res.status(400).json({message: '使用者未登入',error: error});
    		});
    
    	  } else {
    		// 沒有拿到token 返回錯誤 
    		return res.status(403).send({
    		  success: false,
    		  message: '沒有找到token.'
    		});
    
    	  }
    	});
    
    
    	//獲取加密的資訊
    	apiRoutes.get('/', function (req, res) {
    	  req.decoded.user.password = undefined;
    	  res.json(req.decoded.user);
    	});
    
    	//獲取所有使用者
    	apiRoutes.get('/list', function (req, res) {
    	  User.find({}, function (err, users) {
    		res.json(users);
    	  });
    	});
    
    	// 註冊API路由
    	app.use('/api', apiRoutes);
    
    
    複製程式碼

成東

廣州蘆葦科技Java開發團隊

蘆葦科技-廣州專業網際網路軟體服務公司

抓住每一處細節 ,創造每一個美好

關注我們的公眾號,瞭解更多

想和我們一起奮鬥嗎?lagou搜尋“ 蘆葦科技 ”或者投放簡歷到 server@talkmoney.cn 加入我們吧

NODE + JWT + Mongo(簡單實現許可權管理)

關注我們,你的評論和點贊對我們最大的支援

相關文章