前端面试必备——权限控制

clipboard.png

0.前言

记得当年面试的时候,面试官问我,前端怎么作权限控制,咱也不太会这个,只能尴尬回答道:“都是老大搭的架子,我只负责写业务模块代码”,😭😭😭。
现在本身也作了不少项目了,以为有必有对前端权限控制作一个总结。前端

前端权限控制一直是前端必须掌握的一个知识点,通常来讲稍微正规一点的后台系统确定有权限控制。固然仍是那句老话,前端原本就是不安全的,真正的安全仍是须要后端兄弟去把关,因此后端也必须按作权限控制!咱们前端的权限校验主要的目的是过滤不应有的请求和操做,减小服务端压力。vue

我我的认为前端权限控制应该分为四个方面,接口权限、按钮权限,页面权限,路由权限,下面就分四个部分探讨下权限控制怎么作node

1.接口权限

原则

接口权限最简单,目前通常采用jwt的形式来验证,没有经过的话通常返回401 Authentication Required, 返回登陆页从新登陆
登陆完拿到Token,将token存起来(cookie或者ssessionStorage),每次登陆的时候头部携带token就好了(axios请求拦截器实现)。ios

伪码实现

const {token} = login()
cookie.set('token',token)
axios.interceptors.request.use(config => {
        config.headers['token'] = cookie.get('token')
    return config
})
axios.interceptors.response.use(res=>{},{response}=>{
    if (response.data.code === 40099 || response.data.code === 40098) { //token过时或者错误
      router.push('/login')
    }
})

2.按钮权限

原则

一个页面会有新增,删除,编辑等等按钮。不一样用户应该是有不一样操做权限的。
咱们不妨定义权限码 0:不可见 1:不可编辑 2:可编辑
咱们提早和后端约定好按钮的名字,后端会返回一个按钮权限列表。而后咱们根据权限列表使用v-if指令或者 绑定disabled属性达到相应权限效果。
固然更好的最好是本身写一个自定义权限指令,实质就是根据相应权限操做dom面试

伪码实现

好比概览页面的编辑按钮 名字先和后端定义好叫作overview-editvuex

// overviwe.vue  overview是概览页面的路由名
...
<button v-auth='edit'>
...
//util.js 全局注册自定义指令

Vue.directive('auth', {
    inserted: function (el, binding, vnode) {
        const optName = binding.arg
        const authName = `${routeName}-${optName}`     //这里根据路由名和操做类型拼出按钮名 overview-edit
        const btnAuthList = store.state.auth.btnAuthList
        if (btnAuthList[authName]===0) { // 按钮权限为0则移除dom
            el.parentNode.removeChild(el)
        } else if (btnAuthList[authName]===1) { // 按钮权限为1则禁用按钮
            vnode.componentInstance.disabled = true
        }
    }
})

// 登陆的时候接受按钮权限并存在vuex里面
const {btnAuthList} = login()
vuex.state.btnAuthList = btnAuthList

3.页面权限(菜单权限)

我的认为页面权限实际上就是菜单权限,若是说咱们没有去某个页面的导航菜单,实际上就是没有去那个页面的权限了,因此说页面权限的实际就是菜单权限。数据库

原则

一句话,获取菜单权限列表,动态递归生成菜单
这个菜单权限列表能够是后台直接返回你的,也能够是你注册路由的时候写在meta里面的菜单信息,后台返回路由权限,你根据meta信息动态算出的菜单权限。
至于菜单确定是根据菜单权限递归生成的element-ui

伪码实现

//若是是定义在route信息里面会是这种样子
//咱们能够根据后端返回的路由权限结合meta算出菜单权限
{
name:xxx
path:xxx
meta: {
        role: [xxx,xxx,xxx] //哪些角色有资格
        MenuIcon: 'xxxx'  //菜单图标
        MenuTitle: 'xxx' //菜单名
    }
}


//固然也能够麻烦后台直接生成菜单权限返回来
const {menuList} = login()
//存vuex里
vuex.state.menuList = menuList
//在侧边栏或者顶部菜单组件里动态生成菜单
//这里基本都是用的UI库,好比element-ui的NavMenu来实现的,你们有兴趣能够本身看文档,固然也能够本身递归实现,不难
<navMenu/ :menuList=menuList>

4.路由权限

上面的菜单权限虽然作到能看不见菜单,可是我能够经过直接输入url的方式去没有权限的页面呀,这种状况须要靠咱们的路由权限来阻止。axios

原则

这里有两个方案
第一种,也是我目前项目用的,先注册好全部的路由,而后获取有资格访问的路由权限列表,最后直接经过Router.beforeEach来判断,每次跳路由的时候判断是否在权限列表里,在的话就放行,不在就提示权限不够
优势:简单暴力,不会跳到404页面(由于去的路由能在路由规则里找到)
缺点:因为初始化了全部路由,运行的时候会挂载没必要要的路由(?有待考究)
第二种,先只注册基本路由,而后获取路由权限列表,而后借助route.add() API根据权限列表将有权限的路由动态注册到路由规则上
优缺点与第一种正好相反segmentfault

伪码实现

这里只写第一种方案,第二种你们自行google

const {routeAuthList} = login()
cosnt whiteList = ['/login','/','/404']
//合并生成总路由
whiteList = whiteList.contact(routeAuthList)
//存vuex
vuex.state.whiteList = whiteList
//路由守卫判断
router.beforeEach((to, from, next) => {
    //权限校验
    let pass = whiteList.inclue(to);
    if(!pass){
        return console.log('无权访问');
    }
    next();
});

5.讨论

后端返回什么

这个我以为实际没有定论,相关的文章也读了许多,什么作法都有,仍是须要结合实际业务。
好比
1.按钮权限特别少的,那么后端不用返回按钮权限,直接前端生成钮权限就行。甚至不用使用自定义指定,直接v-if,disable就行
2.权限页面特别多,次级路由也特别多,那么也能够前端这边生成路由权限,由于若是后端返的话,每次定义一个次级页面都得让后端在数据库加一条数据,太麻烦人了,不方便
3.后端也不是说非得返回权限路由列表的,像我目前的项目就是返回的菜单列表,而后我根据菜单列表名手动算出权限列表。其实都同样,返回权限列表也是根据权限列表里面的meta算出菜单列表,有毛区别?

缓存什么

关于缓存,你们能够看我这篇文章缓存
获取的我的信息(包括权限列表)该不应缓存到ssessionStorage里面?我看不少人的文章都是只缓存token,每次刷新都是从新拉取信息。
我的认为这样作意义不大,缓存的目的就是为了减小请求,优化交互。存在当前页签基本能保证同一时间你就是你。再说防君子不防小人,至于真的是小人,篡改ssessionStorage数据,咱不是还有后台兄弟的校验吗,怕个卵。

6.总结

总结了前端全部的权限控制,并给出了相应的伪码实现,但愿能给你们带来应该的帮助

相关文章
相关标签/搜索