zoukankan      html  css  js  c++  java
  • 从0到1搭建element后台框架之权限篇

    一、jwt授权认证

    现在大多数项目都是采用jwt授权认证,也就是我们所熟悉的token登录身份校验机制,jwt的好处多多,由于jwt是由服务端生成,中间人修改密串后,服务端会校验不过,安全有效。一般呆在请求头上的Authorization里面。前端童鞋一般获取token后通过vuex存储起来,随后数据持久化存到session中。

    路由跳转验证token

    首先在路由跳转的时候需要验证vuex是否存储了token,如果没有token的话直接跳到登陆页面获取token。

        if (to.path !== '/login' && !store.state.token) {
            next('/login')
            NProgress.done() // 结束Progress
          } else {
            next();
         }

    请求拦截带上token

    详细请看项目中的router.js

    本地存在token之后,我们在每次请求接口的时候都需要带上token来验证token的合法性。

        //在请求前拦截
        if (store.state.token) {
                config.headers["Authorization"] = "Bearer " + store.state.token;
            }

    如果token不合法,全局错误处理,直接跳到登陆页面

         case 401:
            messages("warning", "用户登陆过期,请重新登陆");
            store.commit('COMMIT_TOKEN','')
            setTimeout(() => {
                router.replace({
                    path: "/login",
                    query: {
                        redirect: router.currentRoute.fullPath
                    }
                });
            }, 1000);
            break;

    详细代码看项目中的request.js

    二、菜单权限

    本项目中,我主要是通过后端传过来的角色类型来判断导航菜单的显示与隐藏。
    也就是说首先前端请求接口,后端返回token,以及对应的角色,比如项目中用admin登陆的话,roles=['admin'],用user登陆的话roles=['user']

    接下来我这边设计了一份菜单表和一份路由表,路由表主要是为了注册路由,不需要考虑层级关系。而菜单表需要考虑层级关系,里面可以配置主菜单,子菜单,图标等等一系列的东西,当然菜单表最好是通过接口数据从后端传过来。值得注意的是无论是菜单表,还是路由表,里面都有一个meta配置项。里面可以配置我们的角色权限。路由表对应的菜单表角色权限需要一致。没有配置角色权限的菜单默认都开放。

    menu.js

        {
            icon: "el-icon-question",
            index: "premission",
            title: "权限测试",
            subs: [{
                index: "permission",
                title: "菜单测试",
                meta: {
                    roles: ['admin']
                }
            },
            {
                index: "permissionBtn",
                title: "按钮权限",
            },
        
            ]
        }

    router.js

       {
          path: '/permission',
          component: getComponent('permission', 'permission'),
          meta: {
            title: '菜单权限',
            roles: ['admin']
          }
        },

    根据角色过滤菜单

    现在我们开始编写菜单逻辑,进入Aside.vue,首先根据角色过滤菜单表menu.js

        /**
         * @param {Arrary} menus 菜单
         * @param {Arrary} roles 角色
         * @return {Arrary} res 过滤后的菜单
         */
        filterMenus(menus, roles) {
          const res = [];
          menus.forEach(route => {
            const tmp = { ...route };
            //hasPermission判断权限是否匹配
            if (this.hasPermission(roles, tmp)) {
              if (tmp.subs) {
                tmp.subs = this.filterMenus(tmp.subs, roles);
              }
              res.push(tmp);
            }
          });
          return res;
        },
        /**
         * 通过meta.role判断是否与当前用户权限匹配
         * @param roles
         * @param menu
         */
        hasPermission(roles, menu) {
          if (menu.meta && menu.meta.roles) {
            return roles.some(role => menu.meta.roles.includes(role));
          } else {
            return true;
          }
        },

    过滤结果

        computed: {
            items() {
              let items = this.filterMenus(menu, this.$store.state.roles);
              return items;
            }
          },

    这样就获得了权限菜单

    到目前为止,权限控制基本完成,不过在项目运行的过程中,还发现一个bug。本项目中存在一个tagList,也就是打开的导航标签,当用户从admin切换到user的时候打开的导航标签依旧存在,也就是说用户可以通过导航标签进入premission页面。此时我这边直接通过路由拦截来处理此时的情况。

        if(to.meta.roles){
            to.meta.roles.includes(...store.getters.roles)?next():next('/404')
          }else{
            next();
         }

    没有权限的页面一律进入404页面。

    三、按钮权限控制

    按钮级别的权限说实话一般都通过数据接口来控制是否展示,点击等等情况。如果光有前端来控制绝对不是可行之道。

    项目中按钮权限注册全局自定义指令来完成的。首先src下面新建一个directive文件夹,用于注册全局指令。在文件夹下新建一个premissionBtn.js。如果对自定义指令不熟的话可以查阅官方文档

    全局指令

        import Vue from 'vue'
        import store from '@/store/store'
        //注册一个v-allowed指令
         Vue.directive('allowed', {
            inserted: function (el, bingding) {
                let roles = store.getters.roles
                //判断权限
                if (Array.isArray(roles) && roles.length > 0) {
                    let allow = bingding.value.some(item => {
                        return roles.includes(item)
                    })
                    if (!allow) {
                        if (el.parentNode) {
                            el.parentNode.removeChild(el)
                        }
                    }
                }
            }
        })

    引用

    import './directive/premissionBtn'

    那自定义指令如何使用呢?

         <div class="premissionBtn">
            <el-button type="primary" v-allowed="['admin']">我是只有admin的时候才能显示</el-button>
            <br>
            <el-button type="info" v-allowed="['user']">我是只有user的时候才能显示</el-button>
            <br>
            <el-button type="warning" v-allowed="['admin','user']">我是admin或者user才能显示</el-button>
            <br>
            <el-button type="danger">任何角色都可以显示</el-button>
        </div>

    后记

    本项目还有许多需要完善和优化的地方,最后项目存在着不足或者更好的方法,请及时提出来,方便修正。谢谢大家。

    转载:https://segmentfault.com/a/1190000019000771

  • 相关阅读:
    ViewFlow增强onItemClick功能及ViewFlow AbsListView源代码分析
    函数递归与迭代
    UIPanGestureRecognizer上下左右滑动方向推断算法
    Eclipse中的Web项目自己主动部署到Tomcat
    《从程序猿到项目经理》读后感-职业瓶颈
    安卓开发之简单的短信操作模块
    [Swift通天遁地]二、表格表单-(15)自定义表单文本框内容的格式
    [Swift通天遁地]二、表格表单-(14)实时调整表单元素的激活和失效
    [Swift通天遁地]二、表格表单-(13)实时调整表单元素的显示和隐藏
    [Swift通天遁地]二、表格表单-(12)设置表单文字对齐方式以及自适应高度的文本区域TextArea
  • 原文地址:https://www.cnblogs.com/liupengfei13346950447/p/10881526.html
Copyright © 2011-2022 走看看