项目网址: https://gitee.com/vueGitee/vueGitee/tree/master/loginCheck

思路:1: 登录: 用户输入账号密码,向服务器验证是否正确,验证通过,服务器返回一个token(唯一标示用户身份的一个key),前端将token存储于 cookie,vuex UserToken 变量中,路由重定向到 path:'/'

   2:权限验证: main.js 里面添加路由导航守卫

    2.1:  beforeEach 控制路由跳转:UserToken有值的话,判断 vuex/permission 里面的变量permissionList  是否有值,

      没值的话,根据token,调用接口获取用户对应权限,前端会有一份路由表(src/router/dynamic-router.js),它表示了每一个路由可访问的权限 ,动态根据用户的 role 算出其对应有权限的路由,addRoute() 添加路由,并循环显示主页面左边侧边栏的标题,

    2.2:  afterEach:通过vuex,设置主页面右边头部的面包导航, 左边标题栏的选中项

注意事项: 1: UserToken 存储在cookie中,前端设置cookie有效期  ((本项目未实现 :) 后台那边设置 UserToken 的有效期,每次请求接口,都带上token(即axios 封装 请求头里面  config.headers.Authorization = store.state.UserToken

),根据后台返回的状态码,前端做出相应处理。如 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)
      }
    }
src/store/mutations.js
 LOGIN_IN (state, token) {
    // 这步操作,实现了state 中的 UserToken 赋值, 同时执行 set UserToken (value) 方法,把token 值放到了 sessionStorage(或cookie) 里面
    // 因为刷新页面,vuex 变量 中的值 变成默认值 '' ,所以放到本地缓存里面,刷新页面以后,调用 get UserToken () 方法  从本地缓存中获取token取值
    state.UserToken = token
  },
src/store/state.js
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),最终子组件在 

src/pages/layout/component/main-content/content.vue  显示出来
content.vue 代码如下:
<router-view class="content"></router-view>

  axios 封装在   src/config/httpConfig.js 中      src/api/permission.js中根据不同的接口url,生成不同的接口请求方法