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,提示用户未登录
- 目录结构
说明: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);
```