前言:我以后在文章最后再也不說我下篇博文要寫什么,之前說的大家也可以忽略,如果你不忽略,會失望的😄,不過說出去的話還是要表示一下的,簡單介紹一下路由鈎子:
正如其名,vue-router
提供的導航鈎子主要用來攔截導航,讓它完成跳轉或取消。有多種方式可以在路由導航發生時執行鈎子:全局的, 單個路由級的, 或者組件級的。
1、全局鈎子
使用 router.beforeEach
注冊一個全局的 before
鈎子:
var router = new VueRouter({ ... }) router.beforeEach((to, from, next) => { // TODO:處理跳轉邏輯 })
var router = new VueRouter({ routes: [ { path: '/about', component: AboutComponent, beforeEnter: (to, from, next) => { // ... } } ] })
3、組件級鈎子
beforeRouteEnter
- eforeRouteLeave
var Compoent = { template: `...`, beforeRouteEnter (to, from, next) { // 在渲染該組件的對應路由被確認前調用 }, beforeRouteUpdate (to, from, next) { // 在當前路由改變,但是該組件被復用時調用,上篇文章已經使用過 }, beforeRouteLeave (to, from, next) { // 導航離開該組件的對應路由時調用 } }
Ok,上文留的坑表示完了,以后會繼續講的,主要沒有考慮好好的使用場景,就簡單的介紹一下了,這一篇文字內容會比較多,雖然我不太喜歡文字,但是沒辦法,說的少了反而說不清楚,見諒見諒。下文正式開始本篇主要內容。
今天主要說一下前后端分離模式下的認證和授權,講這個也只是心血來潮,大家也可以放松的看一下,一起討論下方案,可以完善一下用於SPA解決方案。
現在前后端分離模式盛行,如果不考慮SEO等影響,SPA不失為一種很好的方案,這里簡單的列一下其與傳統web開發區別:
1、傳統web開發,每次請求都是請求完整的html,而spa每次都是局部請求並且是Ajax的;
2、傳統web開發,數據和格式(data和html)是在服務器端拼接構建,直接返回到瀏覽器端直接渲染;而spa,則是請求html片段后請求數據,在客戶端通過客戶端模版引擎構建后渲染的;
3、傳統web開發,前后端不分離,好多時候前端工作內容就是靜態頁面,所有的業務邏輯都在服務端;前后端分離后,大大增加前端的比重,一定程度上減輕了服務端的負擔,讓前端有了大前端的概念,讓前端升職加薪塊了很多,這是挑戰也是喜事兒,以后再也不會有人說前端是切頁面的了;
4、spa開發模式,前后通過json交互,更加輕量級,后端接口對於前端來說就是數據服務;nodejs的出現,讓前端開發更往后了一層,有了前端的服務端(也就是中間層)的概念。
我在做前后端分離架構時,一般的思路是:nginx作為前端服務器,並負責請求轉發(不加入node層,如果加入node層,可以直接去掉nginx),也就是兼反向代理服務器,后台通過rest接口提供服務;使用node或者nginx的好處是,可以很方便的處理跨域問題,如果不明白的,可百度或留言,今天網絡不給力,很多node模塊安裝不了,只能以偽代碼的方式講思路了,大家見諒。
對於需要授權的服務我們需要覆蓋以下用例:
1、用戶未登錄只能打開登錄頁面;
2、用戶登錄信息有誤,登錄失敗
3、用戶登錄信息正確,服務端分配token,用於請求rest接口
4、用戶登錄后請求資源,可正常返回;
5、用戶登錄后token過期,請求rest接口資源,返回401;
6、附帶無效token請求資源,返回401
針對上述用例,客戶端設計時需要完成如下幾個功能:
1、注冊vue路由鈎子函數,beforeEnter,在每次路由跳轉前,進行路由檢查,判斷token是否存在;如果不存在,則打開到login頁面,如果存在,則可以執行路由next操作
2、針對每次請求的ajax操作,攔截所有請求操作,加入token到http頭;攔截所有響應操作,對401等特殊狀態碼進行處理或者跳轉。
客戶端可能的偽代碼如下:
var LoginComponent = { template: ` <div class="login" > username:<input type="text" v-model="user.username" /> password:<input type="password" v-model="user.password" /> <input type="button" @click="login()" value="login" /> </div> `, data: function () { return { user: { username: '', password: '' } } }, //其它組件省略。。。 methods: { /** * 登錄后保存token到localStorage */ login: function () { ajaxPost('/login', this.user).then(res => { localStorage.setItem('token', res.data.token); //保存后執行跳轉,跳轉到路由query中傳遞的地址 }, err => console.log(err)) } } } var router = new VueRouter({ //TODO:各種路由定義; routes: [ { name: 'login', path: '/loin', component: LoginComponent } ] }); //注冊全局事件鈎子 router.beforeEnter(function (to, from, next) { if (!localStorage.getItem('token')) { next({ path: '/login', query: { redirect: to.fullPath } }) } else { next();//如果存在token、則繼續前進 } });
服務端需要做的工作:
1、判斷是否是登錄請求,如果是登錄請求,不檢查http header中的token;驗證用戶信息,如果驗證通過,則創建token,設置過期時間並返回;如果驗證不通過,則返回錯誤信息即可;
2、在非登錄請求的情況下(這里基於jwt生成token),獲取http header中token,如果獲取不到,則直接返回401,並提示token無效;獲取token后,使用服務端密鑰,對token進行解密,如果解密失敗,則說明token無效,返回401;如果解密成功,則判斷是否過期,如果已過期,則返回401,並提示token已過期。(jwt一般會使用「sub,exp,iat等字段;其中包含了主題部分,創建時間戳等各種,可以滿足絕大多數場景」)
服務端可能的偽代碼如下(基於Express 4.x):
var express = require("express"); var app = express(); //鑒權中間件 app.use(function (req, res, next) { if (req.path === '/login') { //TODO:進行登錄驗證,並響應token res.json({ success: true, data: { token: 'xxxxxx' } }) } else { var token = req.headers['Authorization']; //TODO:判斷請求是否合法 //如果不合法,這里直接返回401 ,並提示信息 if (!valid(token)) { res.status(401) } else { //如果合法 執行next操作 next(); } } }); //其它路由服務 //app.get('xxxx') //...其它路由服務 app.listen(80,function(){ console.log("port 80 is listenning!!!"); })
上面的代碼經過完善后是可以運行的,今天時間比較倉促,就寫這么多吧,雖然我不准備說一下篇的內容是什么,但是下一篇至少要完成這個認證的demo的,對於node平台的基礎知識希望讀者有一個簡單的了解,這樣對后台的處理也會有幫助。
ps:今天家里網絡超級慢,下載一個express模塊近三個小時,重試了好幾次,還是不行,放棄了。下雨網絡也慢,服了。。。