【实战】电商后台管理系统:权限管理


做到了系统的权限管理部分,以前没有接触过,下面来记录一下。

权限管理主要有三步:

  • 根据权限的不同,渲染不同的菜单,显示不同的页面
  • 在页面验证用户权限,防止越权
  • 最后,有些权限是页面内部的,需要使用自定义指令来限制

1. 根据权限渲染菜单

在点击登陆之后,会返回一系列的数据,里面包括该用户所有权限内的菜单,然后根据这个菜单来进行相应的渲染。

(1)在获取到菜单之后,为方便之后使用,将这些数据存储在Vuex以及本地缓存中

state: {
   navBar: {
        active: '0',
        list: []
    }
},
mutations: {
	 // 创建菜单
	 createNavBar(state, menus) {
	     // 获取菜单以及其子菜单
	     let list = menus.map(item => {
	         let submenu = item.child.map(v => {
	             return {
	                 icon: v.icon,
	                 name: v.name,
	                 pathname: v.desc
	             }
	         })
	         return {
	             name: item.name,
	             subAcive: '0',
	             submenu: submenu,
	         }
	     })
	     // 将菜单列表存储在state数据中
	     state.navBar.list = list
	     // 将数据存储在本地sessionStorage中
	     window.sessionStorage.setItem('navBar', JSON.stringify(state.navBar))
	 },
},

(2)在登录页面初始化菜单

// 生成后台菜单
this.$store.commit('createNavBar', data.tree)

(3)在主布局页面获取数据

...mapState({
	navBar : state => state.menu.navBar
}),

这样菜单的初始化就基本完成了,但是我们刷新网页来看。所有的菜单都消失了,这是因为,我们初始化菜单是在登录之后进入页面时完成的,再次刷新页面的时候,不会再执行该方法,所以无法在初始化菜单。

那么,就需要在入口文件处定义一个初始化菜单的方法,只要刷新页面,就调用该方法,初始化菜单。

mutations: {
    //初始化菜单
    initNavBar(state) {
        // 从本地缓存获取菜单
        let navBar = window.sessionStorage.getItem('navBar')
        navBar = navBar ? JSON.parse(navBar) : {
            active: '0',
            list: []
        }
        // 将结果存储在Vuex中,便于后面使用
        state.navBar = navBar
    }
},

APP.vue中,调用该方法:

created(){
 // 初始化菜单
  this.$store.commit('initNavBar')
}

这样,即使每次刷新页面,也会重新初始化菜单了。

2. 验证页面权限

上面解决了根据权限渲染菜单的问题,但是,即使我们没有权限,在浏览器输入权限外的URL地址,还是可以访问到相应的页面,那么我们就需要对用户进行显示限制。

这里主要使用 路由全局前置守卫 来对用户的权限进行管理。在登录之后,返回的数据中,有一个rules字段,里面包含着用户的权限。

(1)在登录的时候,由于后续没有用到的地方,所以获取到的权限数据只需要存到本地缓存即可,不需要存储在Vuex中:

let data = res.data.data
// 存储权限规则
if(data.role && data.role.rules){
   window.sessionStorage.setItem('rules', JSON.stringify(data.role.rules))
}

(2)在router.js中对进行路由进行页面权限的设置

// 全局前置守卫
router.beforeEach((to, from, next) => {
    let token = window.sessionStorage.getItem('token')
    if (token) {
        // 防止重复登录
        if (to.path === '/login') {
            Vue.prototype.$message.error('请不要重复登录')
            return next({ name: from.name ? from.name : 'index' })
        }
        // 页面权限设置
        if (to.name !== 'error_404') {
            // 获取本地存储的权限
            let rules = window.sessionStorage.getItem('rules')
            rules = rules ? JSON.parse(rules) : []
            // 对要跳转到的页面在规则中查找
            let index = rules.findIndex(item => {
                return item.rule_id > 0 && item.desc === to.name
            })
            // 如果没有找到,就告诉用户没有权限,并跳回上一级页面
            if (index === -1) {
                Vue.prototype.$message.error('没有权限')
                return next({ name: from.name ? from.name : 'error_404' })
            }
        }
        next()
    } else {
        // 防止用户未登录时输入URL跳转
        if (to.path === '/login') {
            return next()
        }
        Vue.prototype.$message.error('请先登录系统')
        next({ path: '/login' })
    }
})

这样,页面的权限设置就基本完成了。

需要注意的是,如果一直返回到上一页,还没有,就会一直跳转,就会进入一个死循环,页面无法加载。

这里就是设置了一个404 的页面,如果上一级找不到相应的权限规则,就跳转到404页面,这样就避免了死循环的问题。如果已经是在404页面,就不再进行验证了。

3. 页面内部权限设置

解决完路由跳转的问题,还有一个问题就是,我们只是根据菜单渲染出了页面,但是有些页面内部一些功能,有些用户是没有权限的。这时我们就需要隐藏相应的DOM元素,让用户看不到这功能。

这就用到了Vue的自定义指令,在登录的时候,返回的数据中有一个字段是用户的权限列表,我们根据这个权限列表来控制DOM的显示和隐藏,如果有这个权限,就显示,否则就不显示。

(1)在main.js中自定义指定

// 添加全局自定义指令,其中auth是自定义指令的名称
Vue.directive('auth', {
    // 总共有四个参数,这里只用到了两个
    inserted(el, binding) {
        // 获取用户的所有信息
        let user = window.sessionStorage.getItem('user')
        user = user ? JSON.parse(user) : {}
        // 如果不是超级管理员就进行验证
        if (!user.super) {
            // 获取所有的权限列表
            let rules = user.ruleNames ? user.ruleNames : []
            // 在权限中查找所有的权限的名称
            let v = rules.find(item => item === binding.value)
            // 如果不存在权限,就移除该DOM节点
            if (!v) {
                el.remove()
            }
        }
    }
})

其中, inserted:被绑定元素插入父节点时调用 (仅保证父节点存在,但不一定已被插入文档中)。

指令钩子函数会被传入以下参数:

  • el:指令所绑定的元素,可以用来直接操作 DOM。
  • binding:一个对象,包含以下 property:
    • name:指令名,不包括 v- 前缀。
    • value:指令的绑定值,例如:v-my-directive=“1 + 1” 中,绑定值为 2。
    • oldValue:指令绑定的前一个值,仅在 update 和 componentUpdated 钩子中可用。无论值是否改变都可用。
    • expression:字符串形式的指令表达式。例如 v-my-directive=“1 + 1” 中,表达式为 “1 + 1”。
    • arg:传给指令的参数,可选。例如 v-my-directive:foo 中,参数为 “foo”。
    • modifiers:一个包含修饰符的对象。例如:v-my-directive.foo.bar 中,修饰符对象为 { foo: true, bar: true }。
  • vnode:Vue 编译生成的虚拟节点。移步 VNode API 来了解更多详情。
  • oldVnode:上一个虚拟节点,仅在 update 和 componentUpdated 钩子中可用。

跟多关于Vue自定义指令,可以查看官网的介绍:官网链接

(2)使用自定义指令

下面就该使用刚刚自定义的指令了,我们拿一个来说明:

<el-button size="mini" type="success" @click="append(data)" v-auth="'添加规则'">增加</el-button>

这里是一个添加管理员规则的按钮,但是这个权限不是所有用户都有的,这里将制定的内容定义为一个字符串,只需要和权限中规则进行匹配,如果有这个权限,就显示,否则就移除该节点。

这样就完成了权限的管理。

对于权限管理,应该还有很多其他的方式,值得去探索。主要还是根据项目的需要来使用合适的方法…

最后补充一下关于Vuex和sessionStorage的区别:

  • vuex存储在内存中,sessionStorage是会话存储,在关闭浏览器之后,就会清除
  • vuex可以存储任何类型的数据,sessionStorage只能存储字符串,对于复杂类型,需要使用stringify和parse来处理
  • vuex主要用于组件之间的传值,sessionStorage主要用于不同页面之间的传值
  • 在刷新页面时,vuex数据会丢失,sessionStorage数据不会丢失
  • vuex的数据是响应式的,sessionStorage的数据不是响应式的
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CUG-GZ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值