NODE + JWT + Mongo(简单实现权限管理)

2018-11-262467

title: NODE + JWT + Mongo(简单实现权限管理) tags: NODE,JWT,Mongo

grammar_cjkRuby: true

[toc]

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做简单的实现。

  • 版本号

  • 流程

    流程图

    • 用户还没登录时,只能访问首页、注册、登录接口,如下图

      首页

      注册

      登录

    • 登录过后能获取自己的信息

      获取自己信息

    • 如果没输入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);


```
分享
点赞1
打赏
上一篇:Docker常用命令笔记(一)
下一篇:小程序登录、微信网页授权(Java版)