Skip to content

权限系统

isdream-vue-admin 提供了灵活的权限管理机制,支持路由级权限和按钮级权限。

权限模式

src/config/index.ts 中通过 routesHandlerOptions.setupRoutesType 配置权限模式:

ts
import type { RouteMeta } from 'vue-router'
import type { StorageConfig } from '@/storage'
import type { ServiceTokenConfig } from '@/service'
import type { RoutesHandlerOptions } from '@/router/useRoutesHandler/types'
import { readonly } from 'vue'

export type DefaultRouteMeta = Required<
  Pick<
    RouteMeta,
    | 'keepAlive'
    | 'hiddenInMenu'
    | 'hiddenInBread'
    | 'needLoading'
    | 'needToken'
    | 'needRouteHistory'
  >
>

interface StoreConfig {
  userMenuStorage: boolean
  userPermissionsStorage: boolean
}

export interface AppConfig {
  storeConfig: StoreConfig
  storageConfig: StorageConfig
  serviceTokenConfig: ServiceTokenConfig
  needKeepAlive: boolean
  routerHistory: 'Hash' | 'HTML5'
  defaultRouteMeta: DefaultRouteMeta
  routesHandlerOptions: RoutesHandlerOptions
  routeMainName: string
  routeLoginName: string
  baseUrlApi: string
  baseUrlFile: string
}

const viteEnv = import.meta.env

const config: Readonly<AppConfig> = {
  // store/user
  storeConfig: {
    // storage是否存储userMenu
    userMenuStorage: false,
    // storage是否存储userPermissions
    userPermissionsStorage: false
  },
  // storage
  storageConfig: {
    prefix: 'isdream',
    expires: 7 * 24 * 60 * 60 * 1000,
    version: 1
  },
  // service
  serviceTokenConfig: {
    position: 'headers',
    key: 'Authorization',
    value: 'Bearer TOKEN',
    expires: 7 * 24 * 60 * 60 * 1000
  },
  // router
  routerHistory: 'Hash',
  // `route.component`需要使用keepAlive
  needKeepAlive: true,
  defaultRouteMeta: {
    // 使用KeepAlive进行缓存
    keepAlive: true,
    hiddenInMenu: false,
    hiddenInBread: false,
    // router/guard
    needLoading: false,
    needToken: true,
    needRouteHistory: true
  },

  // router/routes/index `routesHandler`
  routesHandlerOptions: {
    // 可通过 (store/user `setUserMenu`) 重设权限菜单
    // `all`         添加全部路由
    // `roleMenu`    匹配roleMenu,可以改变userMenu名称、层级、顺序等
    // `permissions` 匹配permissions,不能改变userMenu名称、层级、顺序等
    setupRoutesType: 'roleMenu',
    // router.addRoute(`addRouteParentName`, [])
    addRouteParentName: '__ROUTE_TEMP_NAME',
    // 路由扁平化,只注册最后一层route,性能比较高。(但父级route不会注册, 缓存路由较深时推荐使用)
    flatRoutes: true
  },

  // route name
  routeMainName: '__ROUTE_MAIN_NAME',
  routeLoginName: '__ROUTE_LOGIN_NAME',

  // .env
  baseUrlApi: viteEnv.VITE_BASE_URL_API,
  baseUrlFile: viteEnv.VITE_BASE_URL_FILE
}

config.routesHandlerOptions.addRouteParentName = config.routeMainName

export const appConfig = readonly(config)
export default appConfig

全量注册(all)

注册全部路由,不做权限过滤。适用于开发阶段或不需权限控制的场景。

typescript
routesHandlerOptions: {
  setupRoutesType: 'all'
}

角色菜单匹配(roleMenu)

根据后端返回的角色菜单匹配路由,可以自定义菜单名称、层级、顺序。

typescript
routesHandlerOptions: {
  setupRoutesType: 'roleMenu'
}

通过用户 Store 设置角色菜单:

typescript
import { useStores } from '@/store'

const { user } = useStores()

// 设置角色菜单数据
user.setRoleMenu(menuData)

权限标识匹配(permissions)

根据权限字符串匹配路由,无法改变菜单名称、层级和顺序。

typescript
routesHandlerOptions: {
  setupRoutesType: 'permissions'
}

通过用户 Store 设置权限:

typescript
import { useStores } from '@/store'

const { user } = useStores()

// 设置用户权限列表
user.setUserPermissions(['dashboard', 'user:list', 'user:create'])

路由级权限

动态路由由 src/router/useRoutesHandler/ 处理。处理流程:

  1. 读取 src/router/routes/examples/ 下的所有路由模块
  2. 根据 setupRoutesType 配置过滤路由
  3. 动态添加到路由实例

路由定义示例:

typescript
// src/router/routes/examples/components.ts
export default {
  path: '/components',
  name: 'Components',
  meta: {
    title: '组件',
    needToken: true
  },
  children: [...]
}

按钮级权限

使用 v-auth 指令控制按钮级权限:

ts
import type { Directive } from 'vue'
import { checkAuth } from '@/utils'

/*
  const permission = 'test'
  v-auth:test
  v-auth="permission"
*/
export const auth: Directive<HTMLElement, string | undefined> = {
  mounted(el, binding) {
    const { value, arg } = binding
    const permission = value ?? arg
    if (!permission) {
      return
    }

    if (!checkAuth(permission)) {
      el.remove()
    }
  }
}

使用方式

支持两种写法:

vue
<!-- 通过 v-model 绑定权限标识 -->
<el-button v-auth="'user:delete'">删除</el-button>

<!-- 通过指令参数绑定权限标识 -->
<el-button v-auth:userDelete>删除</el-button>

无权限时元素会从 DOM 中移除。

路由守卫

项目内置 6 个路由守卫:

守卫文件功能
useRedirectrouter/guard/useRedirect.ts重定向到第一个叶子节点
useLoadingrouter/guard/useLoading.ts路由切换 loading
useHasTokenrouter/guard/useHasToken.tsToken 校验,未登录跳转登录页
useKeepAliverouter/guard/useKeepAlive.tsKeepAlive 缓存管理
useRouteHistoryrouter/guard/useRouteHistory.ts路由历史(标签页)
useDocumentTitlerouter/guard/useDocumentTitle.ts页面标题

基于 MIT 许可发布