項目網址: https://gitee.com/vueGitee/vueGitee/tree/master/loginCheck前端
思路:1: 登陸: 用戶輸入帳號密碼,向服務器驗證是否正確,驗證經過,服務器返回一個token(惟一標示用戶身份的一個key),前端將token存儲於 cookie,vuex UserToken 變量中,路由重定向到 path:'/'vue
2:權限驗證: main.js 裏面添加路由導航守衛ios
2.1: beforeEach 控制路由跳轉:UserToken有值的話,判斷 vuex/permission 裏面的變量permissionList 是否有值,git
沒值的話,根據token,調用接口獲取用戶對應權限,前端會有一份路由表(src/router/dynamic-router.js),它表示了每個路由可訪問的權限 ,動態根據用戶的 role 算出其對應有權限的路由,addRoute() 添加路由,並循環顯示主頁面左邊側邊欄的標題,vuex
2.2: afterEach:經過vuex,設置主頁面右邊頭部的麪包導航, 左邊標題欄的選中項axios
注意事項: 1: UserToken 存儲在cookie中,前端設置cookie有效期 ((本項目未實現 :) 後臺那邊設置 UserToken 的有效期,每次請求接口,都帶上token(即axios 封裝 請求頭裏面 config.headers.Authorization = store.state.UserTokenapi
),根據後臺返回的狀態碼,前端作出相應處理。如 res.code === 10001 ,表示token失效,toast 提醒,再退出登陸; res.code === 10002,表示網絡異常,前端toast 提醒; 若沒有相應權限.....)瀏覽器
步驟:緩存
1:vuex 聲明變量 (文件路徑:src/store/state.js)服務器
import {setCookie, getCookie} from '../utils/cookie' export default { get UserToken () { // 判斷用戶是否登陸 // return localStorage.getItem('token') // return cookies.get('token') return getCookie('token') }, set UserToken (value) { setCookie('token', value, 10) console.log('getCookie(token)', getCookie('token')) // return localStorage.setItem('token', value) // return cookies.set('token', value) }, // 導航菜單是否摺疊 isSidebarNavCollapse: false, // 麪包屑導航列表 crumbList: [] }
2: 登陸頁面,點擊‘登陸’按鈕,調用 login 函數,調用後臺接口,前端把接口返回數據中的token變量放到 vuex UserToken,而且放在cookie 裏面(防止用戶刷新瀏覽器頁面,vuex 裏面的state恢復初始值 ),設置路由重定向到 ‘/’
async login () { // 此時爲異步函數 try { let data = await login() // await 同步 等待 須要的等到 await 後面的函數執行完之後有了返回結果,才能執行下面的代碼 let token = data.token this.$store.commit('LOGIN_IN', token) this.$router.replace('/') } catch (e) { console.log(e) } }
LOGIN_IN (state, token) { // 這步操做,實現了state 中的 UserToken 賦值, 同時執行 set UserToken (value) 方法,把token 值放到了 sessionStorage(或cookie) 裏面 // 由於刷新頁面,vuex 變量 中的值 變成默認值 '' ,因此放到本地緩存裏面,刷新頁面之後,調用 get UserToken () 方法 從本地緩存中獲取token取值 state.UserToken = token },
get UserToken () { // 判斷用戶是否登陸 // return localStorage.getItem('token') return getCookie('token') }, set UserToken (value) { setCookie('token', value, 10) // cookie 有效期設置爲 10s console.log('getCookie(token)', getCookie('token')) // return localStorage.setItem('token', value) },
3:main.js 添加 路由鉤子函數
router.beforeEach((to, from, next) => { if (!store.state.UserToken) { // some 方法 判斷 即將被打開的路由裏面,是否有 requiresAuth 屬性 ,以此來判斷是否驗證,但凡是有一個取值爲true,則去登陸頁面,去登陸驗證 if (to.matched.length > 0 && !to.matched.some(record => { return record.meta.requiresAuth })) { next() } else { next({path: '/login'}) } } else { if (!store.state.permission.permissionList) { // (!null === true) 取值爲空,說明路由尚未動態建立 store.dispatch('permission/FETCH_PERMISSION').then(() => { next({path: to.path}) }) } else { if (to.path !== '/login') { next() } else { next(from.fullPath) } } } })
沒有UserToken , 不須要驗證的話,直接 next(), 須要驗證的話,跳登陸頁面
有UserToken(已登陸),permissionList 不存在 ,調用 actions 裏面的 FETCH_PERMISSION 方法,去生成動態路由。
4: FETCH_PERMISSION 方法
state: { // 全部路由 permissionList: null, // 導航菜單 slidebarMenu: [], // 當前 active 導航菜單 currentMenu: '' },
async FETCH_PERMISSION ({commit, state}) { let permissionList = await fetchPermission() let routes = recursionRouter(permissionList, dynamicRouter) console.log('routes', routes) let mainContainer = DynamicRoutes.find(v => v.path === '') let children = mainContainer.children children.push(...routes) commit('SET_MENU', children) // 生成側邊欄 setDefaultRoute([mainContainer]) // 初始化路由 let initialRoutes = router.options.routes router.addRoutes(DynamicRoutes) // 生成完成路由表 commit('SET_PERMISSION', [...initialRoutes, ...DynamicRoutes]) //permissionList變量 表示完整的路由,在main.js router.beforeEach鉤子函數中,調用了它
}
5: 路由 router/index.js: 路由一開始只有 /login
// 初始化路由 export default new Router({ routes: [ { path: '/login', component: Login } ] })
// 準備動態添加路由 export const DynamicRoutes = [ { path: '', component: Layout, name: 'container', redirect: 'home', meta: { requiresAuth: true, name: '首頁' }, children: [ { path: 'home', component: Home, name: 'home', meta: { name: '首頁', icon: 'icon-home' } } ] }, { path: '/403', component: Forbidden }, { path: '*', component: NotFound } ]
登陸之後,頁面重定向到 path: '/' 即 path: '', 此時又重定向到子路由 path: 'home', 由於是子路由,因此頁面顯示是 父路由 (父組件:Layout)+ 子路由(子組件:Home),最終子組件在
<router-view class="content"></router-view>
axios 封裝在 src/config/httpConfig.js 中 src/api/permission.js中根據不一樣的接口url,生成不一樣的接口請求方法