Eggjs筆記:關於JWT的接口權限驗證

關於接口的安全驗證

  • 基於 Session 的安全驗證
    • Session 存儲在服務器,用戶用戶比較少的話是一種簡單的安全驗證機制,但是涉及到跨域 的話需要進行一些配置
    • 用戶量非常非常大的話會耗費一定的服務器資源(中小項目不需要考慮)
  • 對請求參數進行加密的簽名驗證
    • 涉及公鑰、私鑰、簽名等
  • JWT
    • JWT 全稱 JSON Web Token,是目前比較流行的另一種跨域身份驗證解決方案
    • 也是被很多人用壞的一種安全驗證機制,具體需要看項目是否適合

關於 JWT的驗證的流程

  • 客戶端請求接口登錄,登錄成功後,服務端通過jwt生成token返回給客戶端
  • 客戶端訪問需要登錄後才能訪問的接口的時候,需要在請求接口的時候攜帶token,服務端獲取token調用jwt驗證token的合法性,驗證不通過則拒絕訪問

Nodejs 中使用 JWT 實現接口的安全驗證

簽發 token

安裝 jsonwebtoken $ cnpm install jsonwebtoken --save

簽發:

var jwt = require('jsonwebtoken'); 
router.get('/login', function (req, res, next) {
    // 三個參數:用戶對象,簽名字符串(最好定義在配置中),過期時間
    var token = jwt.sign({ name: '張三' }, 'this is sign',{ expiresIn:60*60*24});
    res.send(token);
});

Axios 訪問基於 Jwt 的接口

// 存儲服務器簽發的token ... 
var token = ''; // 這是保存的服務器簽發的token, 僞代碼

// 帶token請求接口
axios.get("http://localhost:3000/api/list", {
    auth: {
        username: token,
        password:''
    }
}) 
.then(function(response) {
    // handle success
    console.log(response); })
.catch(function(error) {
    // handle error
    console.log(error); 
    })
.finally(function() {
    // always executed
});

備註:在不同的框架中如:react,vue,angular, 需要封裝通用攔截器,在攔截器中使用,以上僅作爲演示

獲取請求頭裏面的 token

安裝 $ cnpm install basic-auth --save

獲取

router.get('/addressList', function (req, res, next) { 
    var token = auth(req); // 這裏的auth就是 basic-auth
})

驗證客戶端傳過來 token 的合法性

router.get('/addressList', function (req, res, next) { 
    var token = auth(req);
    if(!token) {
        res.send('沒有權限'); 
    }
    
    try {
        var v = jwt.verify(token.name, 'this is sign'); // 驗證token
        // console.log(v);
        res.send(v ? "有權限" : "沒有權限")
    } catch (error) { 
        res.send(error);
    } 
});

備註:上面僅作爲簡單演示,最好做成一箇中間件來處理權限驗證

關於 Jwt 的一些問題

  • JWT 默認是不加密,但也是可以加密的。生成原始 Token 以後,可以用密鑰再加密一次。
  • JWT 不加密的情況下,不能將祕密數據寫入 JWT。
  • JWT 不僅可以用於認證,也可以用於交換信息。有效使用 JWT,可以降低服務器查詢 數據庫的次數。
  • JWT 的最大缺點是,由於服務器不保存 session 狀態,因此無法在使用過程中廢止某個token,或者更改 token 的權限。也就是說,一旦JWT簽發了,在到期之前就會始終有效,除非服務器部署額外的邏輯。
  • JWT 本身包含了認證信息,一旦泄露,任何人都可以獲得該令牌的所有權限。爲了減少盜用,JWT的有效期應該設置得比較短。對於一些比較重要的權限,使用時應該再次對用戶進行認證。
  • 爲了減少盜用,JWT 不應該使用 HTTP 協議明碼傳輸,要使用 HTTPS 協議傳輸。

關於jwt的二次簽名驗證

  • 對於某一個接口,如: /api/address?uid=1&pid=2, 對請求的參數進行簽名, “uid=1&pid=2”,通過算法處理 var sign = md5(“uid=1&pid=2” + 私鑰) , 這個私鑰可以是個md5加密後的登錄密碼
  • 這個時候客戶端會有這三個東西: token, 請求的url參數, sign (也就是 前面的password)
  • 服務端獲取客戶端攜帶的token以及url上的參數, 然後比如根據uid查找用戶密碼, 計算出私鑰(私鑰=md5(用戶密碼)), 然後計算出sign
  • 對比客戶端傳遞過來的sign和服務端計算出的sign是否一致, 如果一致則驗證通過
  • 當另一個接口被請求的時候,如:/api/xxx?uid=1&tid=3 同樣的道理,每次因爲參數不同,計算出的sign都是不一樣的,當然如果沒有參數,接口本身其實也可以當做參數處理, 服務器可以通過相同的算法來進行對比,這樣可以進一步阻止了客戶端權限的盜用
  • 當然道高一尺魔高一丈,沒有絕對的安全,如果涉及到一些支付相關的業務, 儘量利用二次加密和https以及儘可能小的過期時間,以及做一些機制對token進行續簽等
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章