什么是JSON Web Token ?
官方给出的定义是:
JSON Web Token(JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、独立的方式,用于安全地在当事人之间传递信息作为一个JSON对象。这些信息可以被验证和信任,因为它是数字签名的。JWTs可以使用一个secret (使用HMAC算法)或使用RSA的公钥/私钥对来签名。 文中我们使用公私钥的加密方式。
结构
由下面三个部分组成一个token字符串
-
Header
- header通常由两个部分组成:令牌的type,即JWT,以及正在使用的散列算法,如HMAC SHA256或RSA。
-
Payload ,包含三个类型,自定义部分可以存储一些信息,如:用户信息、角色等;
-
Signature
- 使用header、payload和secret生成一个签名
工作流程
这里直接使用官网的图
他的优点是什么?
- 使用json传输数据,因此在编码时,也会更小
- 更安全
- 无需在服务端保存相关信息,只需要验证token是否有效即可
代码实现
这里使用express来创建一个服务
-
创建一个入口文件,主要用于一些中间件的挂载
//index.js const express = require('express') const app = express() // 使用body-parser获取请求body const bodyParser = require('body-parser'); const cookieParser = require('cookie-parser') // 引入路由中间件 const routerAdmin = require('./app/router-admin') app.use(bodyParser.json()); // for parsing application/json app.use(bodyParser.urlencoded({ extended: true })); // for parsing application/x-www-form-urlencoded app.use(cookieParser()) // 加载路由模块 app.use('/admin',routerAdmin); app.listen(3000,function(){ console.log('port 3000 start') })
-
然后创建一个 app/router-admin.js 生成需要用到认证的路由中间件,这里我是在mongodb中取的用户信息,也可以自行模拟数据
//router-admin.js const express = require('express') const router = express.Router() var MongoClient = require('mongodb').MongoClient; const jwt = require('jsonwebtoken') const fs = require('fs') // const secretStr = 'sdfsjfklsjfiewjwoieow' // 根据mongodb生成的_id查询数据 var ObjectId = require('mongodb').ObjectId var url = "mongodb://localhost:27017/"; var payload = { user : 'william', admin : true } router.post('/login',function(req,res){ let name = req.body.name, pwd = req.body.pwd; var cert = fs.readFileSync('./private.key') MongoClient.connect(url, function(err, db) { if (err) throw err; var dbo = db.db("blog"); var noSqlStr = {name:name,pwd:pwd} dbo.collection("userlist"). find(noSqlStr).toArray(function(err, result) { // 返回集合中所有数据 if (err) throw err; // console.log(result); // 验证通过,服务端回传token if(!!result.length){ var token = jwt.sign(payload, cert, { algorithm: 'RS256' ,expiresIn:'30s'}); res.send({ status : true, msg : '', token : token }) } db.close(); }); }); }) // 验证jsonwebtoken是否过期的中间件,在login接口后面执行,除了login接口的请求外,其他接口都需要验证token router.use(function jwtVerify(req, res, next) { let token = req.get('token') console.log(token) var cert = fs.readFileSync('./public.key'); // 先解密 jwt.verify(token, cert,function(err,decoded){ if(err || !decoded) res.send({data:null,status:false,msg:err}) if(decoded.user == payload.user){ next(); } }); }); router.get('/search',function(req,res){ res.send({data:'查询成功',msg:'',status:true}) }) module.exports = router
-
因为这里使用的是公私钥的加密方式,需使用ssh-keygen生成公私钥
私钥生成:ssh-keygen -t rsa -b 2048 -f private.key 公钥生成:openssl rsa -in private.key -pubout -outform PEM -out public.key
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。