• 前端面试:权限控制


    0.前言

    记得当年面试的时候,面试官问我,前端怎么做权限控制,咱也不太会这个,只能尴尬回答道:“都是老大搭的架子,我只负责写业务模块代码”。
    如今自己也做了很多项目了,觉得有必有对前端权限控制做一个总结。

    前端权限控制一直是前端必须掌握的一个知识点,一般来说稍微正规一点的后台系统肯定有权限控制。当然还是那句老话,前端本来就是不安全的,真正的安全还是需要后端兄弟去把关,所以后端也必须按做权限控制!我们前端的权限校验主要的目的是过滤不该有的请求和操作,减少服务端压力。

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

    1.接口权限

    原则

    接口权限最简单,目前一般采用jwt的形式来验证,没有通过的话一般返回401 Authentication Required

    登录完拿到Token,将token存起来(cookie或者ssessionStorage),每次登录的时候头部携带token就行了(axios请求拦截器实现)。

    伪码实现

    const {token} = login()
    cookie.set('token',token)
    axios.interceptors.request.use(config => {
            config.headers['token'] = cookie.get('token')
        return config
    })

    2.按钮权限

    原则

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

    伪码实现

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

    // 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信息动态算出的菜单权限。
    至于菜单肯定是根据菜单权限递归生成的

    伪码实现

    //如果是定义在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的方式去没有权限的页面呀,这种情况需要靠我们的路由权限来阻止。

    原则

    这里有两个方案
    第一种,也是我目前项目用的,先注册好所有的路由,然后获取有资格访问的路由权限列表,最后直接通过Router.beforeEach来判断,每次跳路由的时候判断是否在权限列表里,在的话就放行,不在就提示权限不够

    优点:简单暴力,不会跳到404页面(因为去的路由能在路由规则里找到)

    缺点:由于初始化了所有路由,运行的时候会挂载不必要的路由(?有待考究)
    第二种,先只注册基本路由,然后获取路由权限列表,然后借助route.add() API根据权限列表将有权限的路由动态注册到路由规则上
    优缺点与第一种正好相反

    伪码实现

    这里只写第一种方案,第二种大家自行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();
    });

    资源搜索网站大全 https://www.renrenfan.com.cn 广州VI设计公司https://www.houdianzi.com

    5.讨论

    后端返回什么

    这个我觉得实际没有定论,相关的文章也读了许多,什么做法都有,还是需要结合实际业务。
    比如
    1.按钮权限特别少的,那么后端不用返回按钮权限,直接前端生成钮权限就行。甚至不用使用自定义指定,直接v-if,disable就行
    2.权限页面特别多,次级路由也特别多,那么也可以前端这边生成路由权限,因为如果后端返的话,每次定义一个次级页面都得让后端在数据库加一条数据,太麻烦人了,不方便

    3.后端也不是说非得返回权限路由列表的,像我目前的项目就是返回的菜单列表,然后我根据菜单列表名手动算出权限列表。其实都一样,返回权限列表也是根据权限列表里面的meta算出菜单列表,有毛区别?

    缓存什么

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

  • 相关阅读:
    JavaScript访问ab页面定时跳转代码
    http协议相关-待续
    curl发送get和post请求
    Java入门——动态网页jsp(jdk下载和配置环境变量)
    LeetCode:Best Time to Buy and Sell Stock
    LeetCode:Reverse Integer
    LeetCode:Same Tree
    LeetCode:Single Number II
    LeetCode:Single Number
    LeetCode:Minimum Depth of Binary Tree
  • 原文地址:https://www.cnblogs.com/xiaonian8/p/14113524.html
Copyright © 2020-2023  润新知