第四章🚦全局前置守卫

142 阅读3分钟

🧑‍🎓 个人主页:SilenceLamb

📖 本章内容:【全局前置守卫

image.png

🌳Gitee仓库地址:👉🏽全局前置守卫

一、获取用户信息

🍑存储用户信息

state: {
    token: getToken(),
    name: '',
    avatar: '',
    roles: [],
    permissions: []
},
  • 👉🏽 操作变量的mutations
mutations: {
    SET_TOKEN: (state, token) => {
        state.token = token
    },
    SET_NAME: (state, name) => {
        state.name = name
    },
    SET_AVATAR: (state, avatar) => {
        state.avatar = avatar
    },
    SET_ROLES: (state, roles) => {
        state.roles = roles
    },
    SET_PERMISSIONS: (state, permissions) => {
        state.permissions = permissions
    }
},
  • 👉 获取用户信息
// 获取用户信息
GetInfo({commit}) {
    return new Promise((resolve, reject) => {
        getInfo().then(res => {
            const avatar = (res.data.user.avatar === "" || res.data.user.avatar == null) ? require("@/assets/images/profile.jpg") : res.data.user.avatar;
            if (res.data.roles && res.data.roles.length > 0) { // 验证返回的roles是否是一个非空数组
                commit('SET_ROLES', res.data.roles)
                commit('SET_PERMISSIONS', res.data.permissions)
            } else {
                commit('SET_ROLES', ['ROLE_DEFAULT'])
            }
            commit('SET_NAME', res.data.user.userName)
            commit('SET_AVATAR',avatar)
            resolve(res)
        }).catch(error => {
            reject(error)
        })
    })
},
avatar: state => state.user.avatar,
userName: state => state.user.userName,
roles: state => state.user.roles,
permissions: state => state.user.permissions,
title: state => state.setting.title,
logo: state => state.setting.logo,

🍑 导航栏添加头像

image.png

image.png

  • 👉🏽 添加用户名
<span class="user-name"> {{ userName }}</span>
  • 👉🏽 添加头像
<img :src="avatar" class="user-avatar" alt="avatar">

二、退出管理系统

image.png

🕰️退出系统action

// 退出系统
LogOut({commit, state}) {
    return new Promise((resolve, reject) => {
        logout(state.token).then(() => {
            commit('SET_TOKEN', '')
            commit('SET_ROLES', [])
            commit('SET_PERMISSIONS', [])
            removeToken()
            resolve()
        }).catch(error => {
            reject(error)
        })
    })
},

🕰️导航栏添加退出

image.png

image.png

<el-dropdown-menu slot="dropdown" class="user-dropdown">
  <el-dropdown-item divided @click.native="logout">
    <span style="display:block;">🍑Log Out</span>
  </el-dropdown-item>
</el-dropdown-menu>

🕰️ 创建退出方法

async logout() {
  await this.$store.dispatch('user/LogOut')
  await this.$router.push(`/login?redirect=${this.$route.fullPath}`)
}

三、路由配置

// 公共路由
export const constantRoutes = [
    {
        path: '/login',
        component: () => import('@/views/login/login'),
        hidden: true
    },

    {
        path: '/404',
        component: () => import('@/views/error/404'),
        hidden: true
    },
    {
        path: '/401',
        component: () => import('@/views/error/401'),
        hidden: true
    },
    {
        path: '/',
        component: Layout,
        redirect: '/index',
        children: [
            {
                path: 'index',
                component: () => import('@/views/index/index'),
                name: 'Index',
                meta: { title: '首页', icon: 'dashboard', affix: true }
            }
        ]
    },
    {
        path: '/system',
        component: Layout,
        name: 'System',
        meta: { title: '系统管理', icon: 'dashboard', affix: true },
        children: [
            {
                path: '/user',
                component: () => import('@/views/system/user/index'),
                name: 'User',
                meta: { title: '用户管理', icon: 'el-icon-user', affix: true }
            },
            {
                path: '/role',
                component: () => import('@/views/system/role/index'),
                name: 'User',
                meta: { title: '角色管理', icon: 'el-icon-s-custom', affix: true }
            },
        ]
    },
]

四、全局前置守卫

import router from './router'
import store from './store'
import {Message} from 'element-ui'
import NProgress from 'nprogress' // progress bar
import 'nprogress/nprogress.css' // progress bar style
import {getToken, removeToken} from '@/utils/token' // get token from cookie


const whiteList = ['/login'] // no redirect whitelist


//全局钩子函数
//在跳转之前执行
router.beforeEach(async (to, from, next) => {
    const hasToken = getToken()
    if (hasToken) {
        if (to.path === '/login') {
            // if is logged in, redirect to the home page
            next({path: '/'})
        } else {
            // determine whether the user has obtained his permission roles through getInfo
            const hasRoles = store.getters.roles && store.getters.roles.length > 0
            if (hasRoles) {
                next()
            } else {
                try {
                    await store.dispatch('user/GetInfo')
                    next({...to, replace: true})
                } catch (error) {
                    removeToken();
                    Message.error(error || 'Has Error')
                    next(`/login?redirect=${to.path}`)
                }
            }
        }
    } else {
        if (whiteList.indexOf(to.path) !== -1) {
            next()
        } else {
            next(`/login?redirect=${to.path}`)
        }
    }
})

router.afterEach(() => {
    NProgress.done()
})
  • 首先调用 getToken 方法,这个方法实际上是去 Cookie 中拿认证 Token,也就是登录成功后后端返回给前端的那个 JWT 字符串。

    • 如果 getToken 方法有返回值,说明用户已经登录了,那么进入到 if 分支中
    • 如果 getToken 没拿到值,说明用户未登录,未登录的话,又分为两种情况:
    • i:访问的目标地址处于免登录白名单中,那么此时直接访问即可;
    • ii:访问的目标地址不在白名单中,那么此时就跳转到登录页面去,跳转的时候同时携带一个 redirect 参数,这样方便在登录成功之后,再跳转回访问的目标页面
  • 如果 getToken 拿到了值,说明用户已经登录了,此时又分情况:如果用户访问的路径是登录页面,那么就给他重定向到项目首页(也就是在已经登录的情况下,不允许用户再次访问登录页面);如果用户访问的路径不是登录页面,那么首先判断 vuex 中的 roles 是否还有值?如果有值,说明当前就是用户点击了一个菜单按钮进行跳转的,那么直接跳转就行了;如果没有值,说明用户是按了浏览器的刷新按钮或者是 F5 按钮刷新进行的页面跳转,那么此时首先调用 getInfo 方法(位于 src/store/modules/user.js 文件中)去服务端重新加载当前用户的基本信息、角色信息以及权限信息。

  • 后期完成: 然后再调用GenerateRoutes方法(位于 src/store/modules/permission.js 文件中)去服务端加载路由信息,并将加载到的路由信息放入到 router 对象中(前提是这个路由对象不是一个 http 链接,就是普通的路由地址)。

  • 🍎main.js引入

import './permission'
  • 🍎路由的配置
  • affix:可以随意命名 true: 需要检查用户是否已登录
{
    path: 'index',
    component: () => import('@/views/index/index'),
    name: 'Index',
    meta: { title: '首页', icon: 'dashboard', affix: true }
}

扫码_搜索联合传播样式-标准色版.png

📢🌥️如果文章对你有帮助【关注👍点赞❤️收藏⭐】