Cette fois, je vais vous montrer comment utiliser vue, vue-router, vuex et addRoutes pour le contrôle des autorisations. Quelles sont les précautions pour utiliser vue, vue-router, vuex et addRoutes pour le contrôle des autorisations, comme suit C'est un cas pratique, jetons-y un coup d'œil.
Tutoriel de contrôle des autorisations basé sur vuex, vue-router, vuex, l'adresse complète du code peut être trouvée sur https://github.com/ linrunzheng/vue-permission-control
Ensuite, simulons le processus d'un utilisateur ordinaire ouvrant le site Web et parcourons l'ensemble du processus étape par étape.
Tout d'abord, commencez par ouvrir le service local localhost:8080. Nous savons qu'après l'ouverture, nous entrerons dans la page de connexion, alors quelle est la base du jugement.
Le premier est le jeton.
Les utilisateurs qui ne sont pas connectés ne pourront pas obtenir le jeton. Pour les personnages connectés, nous enregistrerons le jeton en local ou dans seesionStorage. Par conséquent, vous pouvez savoir si vous devez vous connecter ou non en fonction. s'il existe actuellement un jeton.
Afin d'accéder au token et de faciliter notre fonctionnement, il peut être combiné avec vuex pour mettre en œuvre
/* state.js */ export default { get UserToken() { return localStorage.getItem('token') }, set UserToken(value) { localStorage.setItem('token', value) } } /* mutation.js */ export default { LOGIN_IN(state, token) { state.UserToken = token }, LOGIN_OUT(state) { state.UserToken = '' } }
jugement d'interception
Il n'y a aucun jeton pour accéder à la page qui nécessite une autorisation : rediriger vers la page de connexion
Puisque nos routes sont montées dynamiquement, y compris ' " et 404, lorsqu'aucune route ne correspond, nous redirigerons également pour se connecter
router.beforeEach((to, from, next) => { if (!store.state.UserToken) { if ( to.matched.length > 0 && !to.matched.some(record => record.meta.requiresAuth) ) { next() } else { next({ path: '/login' }) } } })
D'accord, maintenant l'utilisateur ouvre localhost:8080, et le chemin correspondant par défaut est '' Pour le moment, nous n'avons pas monté la route et n'avons pas de jeton, nous venons donc de nous connecter. .
Après avoir entré le nom d'utilisateur et le mot de passe, il y a un jeton. Déclenchez *commit('LOGIN_IN')* via le magasin pour définir le jeton.
Mais il n'y a toujours pas de route. Pour le moment, il n'y a que la route de connexion
/* 初始路由 */ 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: '首页' } } ] }, { path: '/403', component: Forbidden }, { path: '*', component: NotFound } ]
Nous devons aller en arrière-plan pour obtenir les autorisations basées sur le jeton de l'utilisateur actuel.
Comme il y a beaucoup de logique dans les autorisations, un module d'autorisation a été ajouté à vuex pour gérer les autorisations.
Afin de déterminer s'il existe une liste de routes existante, vous devez enregistrer une liste de permissions d'état dans le module d'autorisation de vuex pour juger si la liste de permissions n'est pas nulle, c'est-à-dire qu'il existe déjà une route. Si cela n’existe pas, nous devons travailler.
router.beforeEach((to, from, next) => { if (!store.state.UserToken) { ... } else { /* 现在有token了 */ if (!store.state.permission.permissionList) { /* 如果没有permissionList,真正的工作开始了 */ store.dispatch('permission/FETCH_PERMISSION').then(() => { next({ path: to.path }) }) } else { if (to.path !== '/login') { next() } else { next(from.fullPath) } } } })
Jetons un coup d'œil à ce que fait store.dispatch('permission/FETCH_PERMISSION')
actions: { async FETCH_PERMISSION({ commit, state }) { /* 获取后台给的权限数组 */ let permissionList = await fetchPermission() /* 根据后台权限跟我们定义好的权限对比,筛选出对应的路由并加入到path=''的children */ let routes = recursionRouter(permissionList, dynamicRouter) 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]) } }
Tout d'abord, wait fetchPermission() obtient le tableau d'autorisations donné par l'arrière-plan. . Le format est à peu près le suivant
{ "code": 0, "message": "获取权限成功", "data": [ { "name": "订单管理", "children": [ { "name": "订单列表" }, { "name": "生产管理", "children": [ { "name": "生产列表" } ] }, { "name": "退货管理" } ] } ] }
Deuxièmement, comparez en fonction du tableau de routes que nous avons écrit et filtrez pour obtenir la route que nous voulons
/* 这里是我们写好的需要权限判断的路由 */ const dynamicRoutes = [ { path: '/order', component: Order, name: 'order-manage', meta: { name: '订单管理' }, children: [ { path: 'list', name: 'order-list', component: OrderList, meta: { name: '订单列表' } }, { path: 'product', name: 'product-manage', component: ProductManage, meta: { name: '生产管理' }, children: [ { path: 'list', name: 'product-list', component: ProductionList, meta: { name: '生产列表' } }, { path: 'review', name: 'review-manage', component: ReviewManage, meta: { name: '审核管理' } } ] }, { path: 'returnGoods', name: 'return-goods', component: ReturnGoods, meta: { name: '退货管理' } } ] } ] export default dynamicRoutes
Pour comparaison, j'ai écrit un. fonction récursive , utilisez name et meta.name pour comparer, sur la base de cette fonction, nous pouvons obtenir le résultat que nous voulons
/** * * @param {Array} userRouter 后台返回的用户权限json * @param {Array} allRouter 前端配置好的所有动态路由的集合 * @return {Array} realRoutes 过滤后的路由 */ export function recursionRouter(userRouter = [], allRouter = []) { var realRoutes = [] allRouter.forEach((v, i) => { userRouter.forEach((item, index) => { if (item.name === v.meta.name) { if (item.children && item.children.length > 0) { v.children = recursionRouter(item.children, v.children) } realRoutes.push(v) } }) }) return realRoutes }
Après avoir obtenu le tableau filtré, ajoutez-le aux enfants avec chemin ''
{ path: '', component: Layout, name: 'container', redirect: 'home', meta: { requiresAuth: true, name: '首页' }, children: [ { path: 'home', component: Home, name: 'home', meta: { name: '首页' } }, <!-- 将上面得到的东西加入到这里 --> ... ] }
À l'heure actuelle, les enfants avec le chemin '' sont notre menu de navigation sur la gauche et sont enregistrés dans la barre latéraleMenu d'état pour une utilisation ultérieure. Après avoir ajouté des enfants, DynamicRoutes peut être ajouté à l'itinéraire.
/* 动态添加路由 */ router.addRoutes(DynamicRoutes) /* 初始路由 */ let initialRoutes = router.options.routes /* 合并起来,就是完整的路由了 */ commit('SET_PERMISSION', [...initialRoutes, ...DynamicRoutes])
Une fois l'itinéraire ajouté, c'est-à-dire que l'opération d'action est terminée, vous pouvez appeler next({ path: to.path }) en action.puis pour entrer l'itinéraire. doit être transmis dans suivant C'est-à-dire les informations de routage de la page que vous souhaitez saisir, car une fois le paramètre suivant passé, l'itinéraire actuel que vous souhaitez saisir sera supprimé et l'itinéraire correspondant au paramètre sera saisi. est le même itinéraire, c'est principalement pour garantir que addRoutes prend effet.
Après avoir entré le routage, nous devons commencer à générer le menu de gauche. Nous l'avons déjà enregistré dans sidebarMenu. Il ne nous reste plus qu'à générer le menu de manière récursive. Bien que le menu de navigation de l'élément soit utilisé, pour le routage récursif, nous avons toujours besoin de l'encapsuler vous-même. Le noyau ici est le nom du composant. Là où il y a des enfants dans le composant, vous vous utilisez à nouveau pour parcourir le routage de l'ensemble de l'arborescence.
<template> <p class="menu-container"> <template v-for="v in menuList"> <el-submenu :index="v.name" v-if="v.children&&v.children.length>0" :key="v.name"> <template slot="title"> <i class="iconfont icon-home"></i> <span>{{v.meta.name}}</span> </template> <el-menu-item-group> <my-nav :menuList="v.children"></my-nav> </el-menu-item-group> </el-submenu> <el-menu-item :key="v.name" :index="v.name" @click="gotoRoute(v.name)" v-else> <i class="iconfont icon-home"></i> <span slot="title">{{v.meta.name}}</span> </el-menu-item> </template> </p> </template> <script> export default { name: 'my-nav', props: { menuList: { type: Array, default: function() { return [] } } }, methods: { gotoRoute(name) { this.$router.push({ name }) } } } </script>
Après avoir rafraîchi la page, selon notre routeur.beforeEach jugement, il y a un token mais pas de permissionList Nous allons relancer l'action pour obtenir l'itinéraire, il n'y a donc pas lieu de s'inquiéter. Mais l'effet actif du menu de navigation disparaîtra. Cependant, nous avons défini la clé de el-menu-item sur le nom de l'itinéraire, il nous suffit donc d'attribuer le nom de l'itinéraire actuel à el-menu default-active dans afterEach après l'actualisation. De la même manière, en obtenant tous les itinéraires correspondants après chaque étape, la navigation par fil d'Ariane peut être mise en œuvre.
if (!store.state.permission.permissionList) { store.dispatch('permission/FETCH_PERMISSION').then(() => { next({ path: to.path }) }) } ... router.afterEach((to, from, next) => { var routerList = to.matched store.commit('setCrumbList', routerList) store.commit('permission/SET_CURRENT_MENU', to.name) })
退出登陆后,需要刷新页面,因为我们是通过addRoutes添加的,router没有deleteRoutes这个api,所以清除token,清除permissionList等信息,刷新页面是最保险的。
最后还有一点,每次请求得带上token, 可以对axios封装一下来处理
var instance = axios.create({ timeout: 30000, baseURL }) // 添加请求拦截器 instance.interceptors.request.use( function(config) { // 请求头添加token if (store.state.UserToken) { config.headers.Authorization = store.state.UserToken } return config }, function(error) { return Promise.reject(error) } ) /* axios请求二次封装 */ instance.get = function(url, data, options) { return new Promise((resolve, reject) => { axios .get(url, data, options) .then( res => { var response = res.data if (response.code === 0) { resolve(response.data) } else { Message.warning(response.message) /* reject(response.message) */ } }, error => { if (error.response.status === 401) { Message.warning({ message: '登陆超时,请重新登录' }) store.commit('LOGIN_OUT') window.location.reload() } else { Message.error({ message: '系统异常' }) } reject(error) } ) .catch(e => { console.log(e) }) }) } export default instance
相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!
推荐阅读:
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!