权限分为后端权限和前端权限
- 后端权限
权限的核心在于服务器中数据的变化,后端才是权限的关键,后端权限通过控制某个用户是否能查询数据,是否能够修改数据等操作
- 前端权限
前端权限本质上就是 控制视图层的展示和前端发送的请求。
- 前端权限的意义:降低非法操作的可能性,尽可能排除不必要的请求,提高用户体验
- 前端权限的控制思路:
1. 菜单的控制 (侧边栏 登陆成功后会拿到权限数据,前端根据权限数据,点击对应的菜单。点击菜单才能看到界面 )
2. 界面的控制 ( 如果用户没有登陆,在地址栏目输入url进入管理界面的地址,需要跳转到登陆页面 ,若是非权限内地址,跳转到404)
3.按钮的控制 (根据权限数据,是否展示可以进行操作的数据 ,修改、新增、删除)
4.请求和响应的控制 ( 用户通过非常规操作,比如通过调试工具将某些按钮变成启用状态,这个时候发的请求,也应该进行拦截 )
vue权限控制的实现
- 菜单的控制 数据一般在登陆获取 在home页面使用 可以把数据用vuex 进行维护
//home
import { mapState } from 'vuex'
computed: {
...mapState([‘list’])
}
created(){
this.menulist = this.$store.state.list
}
数据存在vuex中刷新页面菜单栏会消失 ==>数据不能持久化 需要存储到本地
vuex.Store({
state:{
list:JSON.parse(sessionStorage.getItem(‘list’) || ‘[]’)
},
mutations:{
//修改store里面的数据
setlist(state, data){
state.list = data
sessionStorage.getItem(‘list’,JSON.stringify(data))
}
}
…..
})
退出登陆删除vuex的数据和sessionStorage中的数据
//删除sessionStorage的数据
sessionStorage.clear()
//删除vuex中的数据,让当然的界面刷新
window.location.reload()
- 界面的控制
正常逻辑通过登录进入,用户敲入管理平台的地址,可以跳过登录的步骤,所以在某个时机需要判断用户是否登录
1.判断是否登录?
sessionStorage.setItem(’token’,res.data.token)
2. 判断时机?
全局路由导航守卫
to 要去的路由 / from 当前路由 / next是否放行
router.beforeEach((to, from, next)=>{
if(to.path === ‘/login’){
next()
}else{
const token = sessionStorage.getItem(‘token’)
if(!token){
next(‘/login’)//token 不存在 强制调整login界面
}else{
next()
}
}
})
若用户访问不具备角色的菜单 通过地址栏输入 也需要进行拦截。 roles
- 路由导航守卫
路由导航守卫可以每次路由地址发生变化的时候,从vuex取出list判断用户是否将要访问这个界面,这个用户到底用没有这个权限。
(不具备该权限的路由,routes.js 就不应该加载 就是动态路由的使用了)
- 动态路由
登录之后动态添加 ( 根据用户所具备的权限,动态添加 )
router.js 动态导出动态路由
import store from “@/store”
//映射路由 根据key 动态加载
let ruleMapping ={
}
……………
export function initDynamicRoutes(){
cont currentRoutes = router.options.routes
//根据vuex拿到现在当前菜单 然后动态添加相应的路由页面
cont menulist = store.state.list
menulist.forEach(item=>{ //item 为一级权限
item.forEach(item=>{
//二级权限
const temp = ruleMapping[item.path]
currentRoutes[2].children.push(temp)
})
})
router.addRoutes(currentRoutes)
}
//login.vue
login(){
initDynamicRoutes()
}
//解决刷新浏览器 路由不见 因为动态是在登录之后处理 刷新的话已经跳过登录页了
App.vue中添加
import { initDynamicRoutes } from ‘@/router.js’
created(){
initDynamicRoutes()
}
- 按钮的控制
虽然用户可以看到界面,但是界面的一些按钮用户是没有权限进行操作,用户不具备权限的按钮进行隐藏或者禁用,这块逻辑可以防止自定义指令中
import Vue from 'vue'
import router from './router'
Vue.directive(‘permission’, {
//el 当前使用指令的元素 binding可以得到指令后变跟的数值 如{action:’add’}
inserted:function(el,binding){
const action = binding.value.action
//当前所处的组件的路由规则
const currentRight = router.currentRoute.meta
//判断当前的路由所对应的组件中,如何判断用户是否具备action的权限
if(currentRight){
if(currentRight.indexOf(action)== -1){
//不具备权限
const type = binding.value.effect//禁用
if(type == “disabled”){
el.disabled = true
el.calsslist.add(“is-disabled”)
}else {
el.parentNode.removeChild(el)//删除
}
}
}
}
})
<el-button v-permission=“{action:’add’}”></el-button>
<el-button v-permission=“{action:’edit’,effect:‘disabled“}”></el-button>
- 请求和响应的控制
除了登录请求都得带上token,这样服务器才能鉴别你的身份
如果发出了非权限内的请求,直接在前端访问内阻止,虽然发到服务端也有可能拒绝
//请求拦截
axios.interceptors.request.use(()=>{
//判断action是否存在当前路由的权限中
const action = actionMapping[method]
const rights = router.currentRoute.meta
if(rights && rights.indexOf(action) == -1){
//没有权限提示
return Promise.reject(new Error(‘没有权限’))
}
})
//响应拦截
总结 前端权限的控制必须有后端数据支持,否则无法实现
1.菜单控制
- 权限的数据需要在多组件共享,因此采用vuex
- 防止刷新界面,权限数据丢失,所以存储在sessionStorage,并且保证两者同步
2.界面控制
- 路由的导航守卫可以防止跳过登录界面
- 动态路由可以让不具备权限的界面的路由规则 压根不存在
3.按钮控制
- 路由规则中可以增加路由元数据meta
- 通过路由对象可以得到当前路由的规则,以及存储在meta中的数据
4.请求和相应控制
- 请求拦截器和相应拦截器的使用
- 请求方式约定restful