第一步:路由攔截
首先在定義路由的時候就須要多添加一個自定義字段requireAuth,用於判斷該路由的訪問時候須要登陸。若是用戶已經登陸,則順利進入路由,不然就進入登陸頁面。前端
const routers=[ { path:'/', name:'/', component:Index }, { path:'/index', name:'index', meta:{ requireAuth:true,//添加該字段,表示進入這個路由是須要登陸的。 }, component:index }, { path:'/login', name:'login', component:Login }, ] //定義完路由後,咱們主要是利用vue-router提供的鉤子函數beforeEach()對路由進行判斷。 router.beforeEach((to,from,next)=>{ if(to.meta.requireAuth){//判斷該路由是否須要登陸權限。 if(store.state.token){//經過vuex state獲取當前的token是否存在。 next(); }else{ next({ path:'/login', query:{redirect:to.fullPath}//將跳轉的路由path做爲參數,登錄成功後跳轉到該路由 }) } }else{ next(); } })
每一個鉤子方法接收三個參數:
*to:Route:即將要進入的目標路由對象。
*from:Route:當前導航正要離開的路由。
*next:Function:必定要調用該方法來resolve這個鉤子。執行效果依賴next方法的調用參數。
*next();進行管道中的下一個鉤子。若是所有鉤子執行完了,則導航的狀態就是confirmed。
*next(false):中斷當前的導航。若是瀏覽器的URL改變了,那麼》URL地址會重置到from路由對應的地址。(多是用戶手動或者瀏覽器後退按鈕)
*next('/')或則next({path:'/'}):跳轉到一個不一樣的地址。當前的導航被中斷,而後進行一個新的導航。
確保要調用next方法,不然鉤子就不會被resolved。vue
其中,to.meta中是咱們自定義的數據,其中就包括咱們剛剛定義的requireAuth字段。經過這個字段來判斷該路由是否須要登陸權限。須要的話,同時當前應用不存在token,則跳轉到登陸頁面,進行登陸。登錄成功後跳轉到目標路由。
登陸攔截到這裏就結束了碼?並無。這種方式只是簡單的前端路由控制,並不能真正的阻止用戶訪問須要登錄權限的路由。還有一種狀況是:當前token失效了,可是token依然保存在本地。這時候你去訪問須要登錄權限的路由時,實際上應該讓用戶從新登陸。
這時候就須要結合http攔截器+後端接口返回的http狀態碼來判斷。
第二步:
要想統一處理http請求和響應,就得用axios的攔截器。經過配置http response inteceptor,當後端接口返回401,讓用戶從新登陸。ios
//http request攔截器。 axios.interceptors.request.use( config=>{ if(store.state.token){ config.headers.Authorization = `token${store.state.token}`; } return config; }, err=>{ return Promise.reject(err); } ); //http response攔截器 axios.interceptors.response.use( response=>{ return response; } error=>{ if(error.response){ switch(error.response.status){ case 401: //返回401清楚token信息並跳轉到登錄頁面 store.commit(types.LOGOUT); router.replace({ path:'/login', query:{redirect:router.currentRoute.fullPath} }) } } return Promise.reject(err.response.data)//返回接口返回的錯誤信息。 } )
補充一個最全的axios的配置增長了get和post的方法封裝,由於post方法傳參老是須要qs來序列化請求參數。vue-router
//請求攔截、相應攔截、錯誤統一處理。 import axios from 'axios'; import QS from 'qs'; import store from '../store/index'; //環境的切換 if(process.env.NODE_ENV == 'development'){ axios.defaults.baseUrl = '/api'; }else if(process.env.NODE_ENV == 'debug'){ axios.de faluts.baseURL = ''; }else if(process.env.NODE_ENV == 'production'){ axios.defaults.baseURL= 'http://api.123dailu.com/'; } //請求超時時間 axios.defaults.timeout = 10000; //post請求頭 axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded;charset=UTF-8'; //請求攔截器 axios.interceptors.request.use( config=>{ //每次發送請求以前判斷是否存在token,若是存在,則統一在http請求的header都加上token,不用每次請求都手動添加了。 //即便本地存在token,也有可能token是過時的,因此在響應攔截器中要對返回狀態進行判斷。 const token = store.state.toekn; token && (config.headers.Authorization = toekn); return config; }, err =>{ return Promise.error(err); } ) //響應攔截器 axios.inteceptors.response.use( respones=>{ if(response.status == 200){ return Promise.resolve(response); }else{ return Promise.reject(response); } }, //服務器狀態碼不是200的狀況 error=>{ if(error.response.status){ switch(error.response.status){ //401:未登陸 //未登陸則跳轉登陸頁面,並攜帶當前頁面的路徑。 //在登陸成功後返回當前頁面,這一步須要在登陸頁操做。 case 401: router.replace({ path:'/login', query:{redirect:router.currentRoute.fullPath} }); break; //登陸過時對用戶進行提示。 //清除本地token和清空vuex中的token對象。 //跳轉登陸頁面。 case 403: Toast({ message:'登陸過時,請從新登陸', duration:1000, forbidClick:true }); //清除token localStorage.removeItem('token'); store.commit('loginSuccess',null); //跳轉登錄頁面,並將要瀏覽的頁面fullPath傳過去,登陸成功後跳轉須要訪問的頁面。 setTimeout(() => { router.replace({ path: '/login', query: { redirect: router.currentRoute.fullPath } }); }, 1000); break; } return Promise.reject(error.response); } } )
/** * get方法,對應get請求 * @param {String} url [請求的url地址] * @param {Object} params [請求時攜帶的參數] */ export const get =(url, ...params)=>{ return new Promise((resolve, reject) =>{ axios.get(url, { params: params }) .then(res => { resolve(res.data); }) .catch(err => { reject(err.data) }) }); } /** * post方法,對應post請求 * @param {String} url [請求的url地址] * @param {Object} params [請求時攜帶的參數] */ export const post = (url,... params) =>{ return new Promise((resolve, reject) => { axios.post(url, QS.stringify(...params)) .then(res => { resolve(res.data); }) .catch(err => { reject(err.data) }) }); }
1.安裝vue-cookiesvuex
npm install vue-cookies --save;
2.在登陸接口中設定cookiesnpm
this.$http.post(global.domin+'/login/check',{ uesrname:this.ruleForm.username, password:this.ruleForm.password }).then(function(response){ var dataObj = respones.data; if(dataObj.code==200){ that.token = dataObj.data.token; that.$cookies.set('token',that.token,'45d');//第三個參數是過時時間。 } }).catch(function(error){ console.log(error); })
3.在main.js中設置攔截器。axios
//攔截器 每一個接口加token axios.interceptors.request.use(function(config){ if(VueCookies.get('token')){ config.headers.Authorization = String(VueCookies.get('token')) //具體是什麼樣的頭,和後端匹配。 }; return config; },function(error){ return Promise.reject(error); }); //沒有就從新登陸 axios.interceptors.response.use(function(response){ // console.log(response) // if(response.data.code == 401) { // router.replace({ // name: 'login' // }); // } return response; },function(error){ if(error.response.status==401){ router.replace({ name:'login' }) } return Promise.reject(error)//用上面的成功的仍是下面報錯的根據需求。 })