天天看點

技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

token驗證的實作方式很簡單,隻需要在所有後端接口中添加一個驗證是否存在token的中間件即可,接口的通路過程是調用→運作→傳回資料。是以我們在接口調用之後、運作之前的位置加一個驗證token的函數作為接口的中間件,進而驗證到非登入人員,将其頁面跳轉到登陸頁面即可。

技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

1.在server端擷取admin端sessionStorage(或localStorage)存儲的token

我們要通過将sessionStorage傳入請求頭的方式在server端擷取頁面存儲的token。這樣做可以避免修改每一個接口(在每一個接口中擷取token,再傳到背景),背景可以直接在請求頭中擷取需要的token值。

方法是:在http.js中全局設定擷取token,将token值傳入請求頭**Request

Headers**中,然後背景接口中直接從請求頭中擷取token,進而實作驗證。

(1)使用axios裡的Interceptors方法

在npm官網查詢axios
技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

admin/http.js前端admin端将token傳入請求頭Request Header:

技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)
// 使用axios的interceptors攔截器,将http調用時攔截
http.interceptors.request.use(function (config) {
    // 将token值傳入請求頭,"Bearer+空格"是行業規範,一看見Bearer(持票人,也就是被校驗者)就知道是token驗證
    config.headers.Authorization = 'Bearer ' + sessionStorage.token
    return config;
}, function (error) {
    return Promise.reject(error);
});           

(2)server後端接口處接收請求頭中的token值

server/routes/admin/index.js,添加中間件後的建立資料接口:

// 建立資料(增)
    router.post('/', async(req, res, next) => {
        // 擷取請求頭中的token
        // 1.前端的authorization首字母大寫,後端小寫,自動對應
        // 2.擷取到的有可能為空值
        // 3.由于根據代碼規範傳入的token值帶有Bearer和空格,是以用split方法找到空格,在空格處分離Bearer和token值形成數組
        // 4.再使用pop方法提取數組中最後一個值(也就是token值)
        const token = String(req.headers.authorization || '').split(' ').pop() 
        // 使用jwt提取token資料(解密),當時我們傳入的是使用者id,是以解密出的就是使用者id和一個自帶參數
            // 引入jsonwebtoken
        const jwt = require('jsonwebtoken')
        // 1.jwt的verify為解密方法
        // 2.解密方法與加密方法相同,對token進行解密,需要用到全局定義的secret密鑰
        // 3.利用解構指派{}方法将id解構
        const { id } = jwt.verify(token, app.get('secret'))
        // 利用id查找是否有此使用者id,以防僞造jwt登入
            // 引入model模型
       // const Admin = require('../../models/Admin')
            // 查詢id,将查詢到的user放入req,友善其他接口也能夠使用
       // req.user = await Admin.findById(id)
        console.log(id)
        // 執行下一步
        await next()
    }, async(req, res) => {
        // const Model = require('../../model/' + req.params.resourse)
        const model = await req.Model.create(req.body)
        res.send(model)
    })           

建立一個分類,測試檢視終端查詢到的req.user:

技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

沒問題,檢視Request Header:

技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

3.http-assert 驗證提示工具

如果登陸異常狀态下無故跳轉到登入頁,使用者會以為網站有問題吧,是以我們要像登入接口一樣,發送錯誤狀态碼和錯誤資訊。

我們在登入接口中使用的發送錯誤資訊方式是:

// 如果使用者名為空
        if(!username){
            return res.status(422).send({
                message: '請輸入使用者名'
            })
        }           

有一個工具,可以用一行代碼将這一段替代,http-assert(用于測試函數、值是否存在、是否正确的工具包)。

使用方法:

cd server           
npm i http-assert           

安裝并引入:

技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)
// 如果使用者名為空
        // if(!username){
        //     return res.status(422).send({
        //         message: '請輸入使用者名'
        //     })
        // }

        // assert方式修改後
        assert(username, 422, '請輸入使用者名')
        // 是否有username, 沒有就報錯422, 報錯資訊是‘’           
技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

測試:

技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

報錯422沒問題,但是message沒有接收到。是因為http-assert是以抛出異常的方式進行報錯的,前端無法擷取到json資料。

是以我們要寫一個錯誤處理函數,對抛出的異常做處理,将異常中的内容進行捕獲并傳給前端admin。

// 錯誤處理函數(中間件)
    app.use(async(err, req, res, next) => {
        // 如果發送錯誤碼,将錯誤碼放到res輸出到前端顯示
        // 如果擷取不到狀态碼,就是500錯誤,是以狀态碼報錯或500報錯
        res.status(err.statusCode || 500).send({
            message: err.message
        })
    })           
技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

在登入頁測試,沒問題:

技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

可以将此類操作都改成這個格式,我這裡隻在token判斷中間件裡添加:

技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

删除sessionStorage中的登入狀态token:

技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

建立資料進行測試,出現了新問題:

技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

意思是jwt格式錯誤,是jwt包傳遞過來的資訊,被我們接收并列印出來了。我們看一下Request Header:

技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

應該是我們将token值删除後,jwt不認識undefined,不能将其定義為空,是以我們在前端admin的http.js攔截器函數中進行修改:

技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)
技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

沒問題。

4.如果token驗證未登入,跳轉登入頁。

任何操作中,若驗證出現token報錯,直接跳轉到登入頁即可,我們可以使用錯誤處理函數,将所有token相關的報錯碼寫為401,當報錯401統一跳轉頁面到登入頁。

技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

修改http.js響應攔截函數:

技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

要想使用路由,該頁面上方要引入:

技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)
技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

成功跳轉登入頁。

5.封裝token中間件

中間件内容很多,如果将每個需要用到這個中間件的接口都指派此段内容,代碼就會異常多且亂,是以我們将它封裝成一個函數,使用到時直接把函數名放入即可。

技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

封裝:

技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

使用,在除登入接口以外admin使用的接口都使用此中間件:

技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

sessionStorage.clear()測試:

技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

隻要使用到接口的地方,就會直接跳轉登入頁。

6.上傳圖檔的接口錯誤解決

當我們給圖檔上傳接口也添加token中間件後,突破就無法上傳了。

依然報錯401:

技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

看一下network裡邊的接口調用情況,Request Header沒有帶上Authorization:

技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

這是因為我們請求攔截過程中使用的是axios方法中的攔截方法,但是圖檔上傳我們用的是elementUI自帶的上傳請求庫進行圖檔的上傳。

技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

是以修改圖檔上傳功能,SkillSet.vue、AdSet和富文本編輯器等使用到圖檔上傳功能頁面中圖檔上傳加一個傳遞header的方法:

(1)在全局添加token到header的方法,使用mixin()全局定義方法:

技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

(2)使用全局定義的getAuthHeaders()函數方法:

技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

在建立技能頁面測試:

技能學習:學習使用Node.js + Vue.js,開發前端全棧網站-12-3.登陸的token驗證(校驗登入)

沒問題,之後我們在所有圖檔上傳的元件中添加

:headers="getAuthHeaders()"

即可。

7.總結

隻要我們确立好實作token驗證的過程方向後就可以完成這個功能。登入的token驗證過程非常簡單,就是調用接口→發送token→接收token→判斷token→将token判斷結果傳給前端→如已登入運作接口(若未登入跳轉登入頁)→傳回資料,我們的搭建過程就是對每個步驟進行逐一尋找找方法、解決。

另外,在某些沒有使用接口的頁面上,比如建立廣告位功能,在儲存之前沒有任何接口操作,頁面就不會進行強制跳轉登入頁面的動作。是以我們需要做前端路由校驗,見下篇文章。

繼續閱讀