vue项目实践-前后端分离关于权限的思路

前后端分离后权限的思路

最近看到许多关于权限的思路,但好像都是使用动态加载路由的方式,现在也分享下我在项目中使用的解决方案。 前后端分离关于权限的处理每个人都不一样,根据项目选择制定合适的方案就好

我的方案是:

  • 前端挂载所有路由
  • 通过 Api 接口获取用户权限标识(路由名称)
  • 在路由切换的时候进行权限校验
  • 至于页面的权限按钮则通过指令+自定义组件的形式封装成通用权限按钮,通过传入相应的标识判断是否现实按钮
  • 大体流程如下图所示

前后端分离权限的实现

  1. 路由中定义是否需要验证权限:meta:{ auth :true }

路由定义

若是后端项目,一般会包含公用的头部,侧边导航等公用的部分,这些部分可以将其抽象成一个个组件,创建布局页使其更简单的使用关于路由的引用,在大的项目中发现不适用懒加载能够更快的热更新,所以可以根据环境采取不同的加载方式一个简单的路由

路由结构图

  • _import.[env].js:

生产环境( production )/ testing 的定义 module.exports = file => () => import('@/views/' + file + '.vue') 开发环境( development )的定义 module.exports = file => require('@/views/' + file + '.vue').default 路由导入代码

  • index.js : 使用 vue-router 挂载路由
import Vue from 'vue'
import Router from 'vue-router'
import { routes } from './routes'
import logic from './logic'
Vue.use(Router)

const router = new Router({
  //   mode: 'history',
  routes
})
router.beforeEach(logic.beforeEach)
router.afterEach(logic.afterEach)

export default router
  • logic.js : 路由钩子的实现
import { getInfo } from '@/api/modules/account'
const beforeEach = (to, from, next) => {
  if (!to.meta.auth) {
    return next()
  }
  if (!localStorage.token) {
    return next('/login')
  }
  if (window.info) return next()
  getInfo().then(res => {
    localStorage.token = res.data.info.token
    window.info = res.data.info
    window.menus = res.data.menus
    window.modules = res.data.modules
    next()
  })
}
const afterEach = (to, from) => {}

export default {
  beforeEach,
  afterEach
}
  • routes.js:路由的模块定义
const _import = require('./_import_' + process.env.NODE_ENV)

export const appRouter = [
  {
    path: '/',
    component: Layout,
    children: [
      {
        path: '',
        name: 'home',
        component: _import('dashboard/index'),
        meta: { defAuth: true, auth: true }
      }
    ]
  }
]
export const routes = [...appRouter]

接口定义

  • account/login 登录成功返回 token,保存到本地跳转页面
  • auth/info 校验是否有 token 信息及登录信息,无则发送请求获取登录信息,菜单及权限模块标识列表

菜单加载

新建 Layout 文件夹,将各部分组件再拆成小组件进行拼接后台组件,样式使用圣杯布局,然后稍加改动就能够实现基本的后台管理页布局 Layout 结构图

菜单结构:

"menus": [
      {
        "menuName": "控制台",
        "menuIcon": null,
        "menuCode": "home",
        "menuUrl": null
      },
      {
        "menuName": "系统管理",
        "menuIcon": null,
        "children": [
          {
            "menuName": "管理员管理",
            "menuIcon": null,
            "children": [
              {
                "menuName": "管理员列表",
                "menuIcon": null,
                "menuCode": "system-admin-list",
                "menuUrl": null
              }
            ]
          },
          {
            "menuName": "角色列表",
            "menuIcon": null,
            "menuCode": "system-role-list",
            "menuUrl": null
          }
        ]
      }
    ],

递归生成菜单组件

<template>
    <dl>
        <template v-for="(item,index) in menus">
            <dt :key="item.menuName">
                <a href="javascript:;" v-if="item.menuUrl" @click="$ui.redirect(item.menuUrl)">{{item.menuName}}</a>
                <router-link :to="{name:item.menuCode}" v-else-if="item.menuCode">{{item.menuName}}</router-link>
                <span v-else>{{item.menuName}}</span>
            </dt>
            <dd class="child-menu" :key="'c_'+index" v-if="item.children&&item.children.length>0">
                <v-app-nav :menus="item.children" />
            </dd>
        </template>
    </dl>
</template>

<script>
export default {
  name: 'v-app-nav',
  props: ['menus']
}
</script>

<style>
</style>

指令封装

可以通过指令传入需要的权限标识值,进行对按钮权限的控制,根据需要控制显示/启用

定义

export default {
  auth: {
    inserted: (el, binding) => {
      if (window.modules.indexOf(binding.value) === -1) {
        // el.remove()
        el.setAttribute('disabled', 'disabled')
      }
    }
  }
}

使用

对于常用的一些按钮,应封装到组件中,统一管理风格,也能使起更易维护

<button v-auth="'role_create_create'">添加</button>

相关链接

文中的实现可以在下面仓库中找到,不清楚的地方可以直接查看源码

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏前端侠2.0

html5 Postmessage解决跨域问题

为了实现不同域之间的通信,需要在操作系统的 hosts 文件添加两个域名,进行模拟。

1832
来自专栏软件测试经验与教训

Fiddler用法整理

读书与实践是获取知识的主要渠道,学习的权力只掌握在每个人自己手中,让学习成为一种生活的习惯,这比任何名牌大学的校徽重要得多!

1311
来自专栏PhpZendo

HTML 5 Web Workers 的基本信息

要将有趣的应用(例如从侧重服务器端的实施)移植到客户端 JavaScript,存在很多制约瓶颈。其中包括浏览器兼容性、静态类型、可访问性和性能。幸运的是,随着浏...

961
来自专栏LIN_ZONE

谷歌断点调试(转载)

简单地说,断点调试是指自己在程序的某一行设置一个断点,调试时,程序运行到这一行就会停住,然后你可以一步一步往下调试,调试过程中可以看各个变量当前的值,出错的话,...

1204
来自专栏PPV课数据科学社区

pyspider 爬虫教程(二):AJAX 和 HTTP

在上一篇pyspider 爬虫教程 (1):HTML 和 CSS 选择教程中,我们使用 self.crawl API 抓取豆瓣电影的 HTML 内容,并使用 C...

3267
来自专栏向治洪

React native开发中常见的错误

react native环境搭建请移步:react native环境搭建 这里说说react native创建完成之后,运行中出现的常见问题, 问题1: jav...

2976
来自专栏HTML5学堂

深入剖析iframe跨域问题

HTML5学堂:本文当中我们介绍了跨域的基本知识,讲解到了跨域的相关种类,并讲解了解决跨域中的一种方法——如何使用iframe跨域。讲解了iframe跨域的基本...

1.6K4
来自专栏日常学python

Ajax网页爬取案例详解

首先列举出一些python中爬虫常用的库,用之前需要先下载好,本文假设你已经安装好相应的库。

2651
来自专栏向治洪

React Native项目组织结构介绍

代码组织: 目录结构: . ├── components //组成应用的各个组件 │   ├── Routers.android.js //每个组...

2357
来自专栏魏艾斯博客www.vpsss.net

WDCP 面板 V3.2 新增多 PHP 版本共存和一键 SSL 功能

1903

扫码关注云+社区