基於jsonwebtoken(JWT) 的web認證 (Node版實現)

什麼是JSON Web Token ?

官方給出的定義是:
JSON Web Token(JWT)是一個開放標準(RFC 7519),它定義了一種緊湊的、獨立的方式,用於安全地在當事人之間傳遞信息做爲一個JSON對象。這些信息能夠被驗證和信任,由於它是數字簽名的。JWTs可使用一個secret (使用HMAC算法)或使用RSA的公鑰/私鑰對來簽名。 文中咱們使用公私鑰的加密方式。html

結構

由下面三個部分組成一個token字符串git

  • Headergithub

    • header一般由兩個部分組成:令牌的type,即JWT,以及正在使用的散列算法,如HMAC SHA256或RSA。
  • Payload ,包含三個類型,自定義部分能夠存儲一些信息,如:用戶信息、角色等;web

    • Registered claims:已註冊的,具體屬性,點擊傳送
    • Public claims:自定義的,具體屬性,點擊傳送
    • Private claims:這是在贊成使用它們的各方之間共享信息的自定義聲明,而且既沒有註冊也沒有公開聲明。
  • Signature算法

    • 使用header、payload和secret生成一個簽名

工做流程

這裏直接使用官網的圖
圖片描述mongodb

他的優勢是什麼?

  1. 使用json傳輸數據,所以在編碼時,也會更小
  2. 更安全
  3. 無需在服務端保存相關信息,只須要驗證token是否有效便可

代碼實現

這裏使用express來建立一個服務
  1. 建立一個入口文件,主要用於一些中間件的掛載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')
    })
  2. 而後建立一個 app/router-admin.js 生成須要用到認證的路由中間件,這裏我是在mongodb中取的用戶信息,也能夠自行模擬數據json

    //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
  3. 由於這裏使用的是公私鑰的加密方式,需使用ssh-keygen生成公私鑰安全

    私鑰生成:ssh-keygen -t rsa -b 2048 -f private.key
        公鑰生成:openssl rsa -in private.key -pubout -outform PEM -out public.key

完整項目地址

參考

  1. https://jwt.io/introduction/
  2. https://tools.ietf.org/html/r...
相關文章
相關標籤/搜索