1. 程式人生 > >koa2服務端使用jwt進行鑑權及路由許可權分發

koa2服務端使用jwt進行鑑權及路由許可權分發

大體思路

  後端書寫REST api時,有一些api是非常敏感的,比如獲取使用者個人資訊,檢視所有使用者列表,修改密碼等。如果不對這些api進行保護,那麼別人就可以很容易地獲取並呼叫這些 api 進行操作。

  所以對於一些api,在呼叫之前,我們在服務端必須先對操作者進行“身份認證”,這就是所謂的鑑權。

  Json Web Token 簡稱為 JWT,它定義了一種通訊雙方之間以 JSON 物件的形式安全傳遞資訊的方法。JWT 可以使用 HMAC 演算法或者是 RSA 的公鑰金鑰對進行簽名,複雜度較高,換來的是更可靠的安全係數。

  整個認證的流程大體如下:

  首先使用者登入的介面是不用token認證的,因為這個介面本身就是token的產生來源。前端輸入使用者名稱和密碼後請求伺服器登入介面,伺服器驗證使用者名稱密碼正確後,生成token並返回給前端,前端儲存token,並在後面的請求中把token帶在請求頭中傳給伺服器,伺服器驗證token有效,才可以進行下一步操作。

 

伺服器生成token

  由於我們的服務端使用 Koa2 框架進行開發,除了要使用到 jsonwebtoken 庫之外,還要使用一個 koa-jwt 中介軟體,該中介軟體針對 Koa 對 jsonwebtoken 進行了封裝,使用起來更加方便。

  

const router = require('koa-router')();
const jwt = require('jsonwebtoken');
const userModel = require('../models/userModel.js');
router.post('/login', async (ctx) => { const data = ctx.request.body;const result = await userModel.findOne({ name: data.name, password: data.password }) if(result !== null){ const token = jwt.sign({ name: result.name, _id: result._id }, 'zhangnan', { expiresIn: '2h' }); return ctx.body = { code: 200, token: token, msg: '登入成功' } }else{ return ctx.body = { code: 400, token: null, msg: '使用者名稱或密碼錯誤' } } }); module.exports = router;

  (注意:這裡暫時不討論加鹽加密校驗,實際專案中密碼不可能這樣明文驗證,這裡只是為了著重討論token鑑權。在驗證了使用者名稱密碼正確之後,就可以呼叫 jsonwebtoken 的 sign() 方法來生成token,接收三個引數,第一個是載荷,用於編碼後儲存在 token 中的資料,也是驗證 token 後可以拿到的資料;第二個是金鑰,自己定義的,隨便寫個什麼單詞都可以,但是驗證的時候一定要相同的金鑰才能解碼;第三個是options,可以設定 token 的過期時間。)

  

前端獲取token

  接下來就是前端獲取 token,這裡是在 vue.js 中使用 axios 進行請求,請求成功之後拿到 token 儲存到 localStorage 中。

  

submit(){
    axios.post('/login', {
        name: this.username,
        password: this.password
    }).then(res => {
        if(res.code === 200){
            localStorage.setItem('token', res.data.token);
        }else{
            this.$message('登入失敗')
        }
    })
}

  然後前端在請求後端api時,就把 token 帶在請求頭中傳給伺服器進行驗證。每次請求都要獲取 localStorage 中的 token,這樣很麻煩,這裡使用了 axios 的請求攔截器,進行全域性設定,對每次請求都進行了取 token 放到 headers 中的操作。

axios.interceptors.request.use(config => {
    const token = localStorage.getItem('token');
    config.headers.common['Authorization'] = 'Bearer ' + token;
    return config;
})

(這段程式碼,如果是vue專案,可以直接放在main.js中設定,表示每次請求前都會往請求頭的authorization裡塞一個token,至於那個Bearer 是koa-jwt的一個標識單詞,方便解析)

  

伺服器驗證token

  接下來伺服器收到前端發過來的token後,就可以進行驗證。

const koa = require('koa');
const koajwt = require('koa-jwt');
const app = new koa();

app.use(koajwt({
    secret: 'zhangnan'
}).unless({
     path: [/\/register/, /\/login/]
}));

(在這裡沒有定義錯誤處理函式,由於出現錯誤後會返回401,所以我直接就讓前端來處理這種異常情況,給出一個錯誤的互動提示即可)

 

分析koa-jwt原始碼

  我們在node_mudules裡面找到koa-jwt/lib/resolvers資料夾下的auth-header.js檔案,看下koa-jwt做了些什麼

  (可以看到它是先判斷請求頭中是否帶了 authorization,如果有,則通過正則將 token 從 authorization 中分離出來,這裡我們也看到了Bearer這個單詞。如果沒有 authorization,則代表了客戶端沒有傳 token 到伺服器,這時候就丟擲 401 錯誤狀態。)

  再看看上一級的vertify.js。

  

  (可以看到在 verify.js 中,它就是呼叫 jsonwebtoken 原生提供的 verify() 方法進行驗證返回結果。jsonwebtoken 的 sign() 方法用於生成 token ,而 verify() 方法當然則是用來解析 token。屬於jwt配對生產的兩個方法,所以koa-jwt這個中介軟體也沒做什麼事,無非就是用正則解析請求頭,呼叫jwt的vertify方法驗證token,在koa-jwt資料夾的index.js中,koa-jwt還呼叫koa-unless進行路由許可權分發)

  以上就是json web token的大體流程。

&n