---
url: /guide/auth.md
---
# 权限验证

在 `apps/<app>/src/api/modules/account.ts` 文件里找到 `permission` 的函数，该函数用于登录成功后获取用户权限。在实际开发中，需要进行修改，框架默认通过假数据模拟获取用户权限。

在演示源码中，默认提供了两组权限，你可以在“权限验证”导航里切换帐号查看不同权限下的效果。

## 路由权限

路由配置里的 [`meta.auth`](router#auth) 配置项就是用来配置路由的权限。

框架内部鉴权的逻辑是字符串比对，所以建议对权限有个统一的格式，例如为 `xxx.yyy` ，其中 `xxx` 表示模块名， `yyy` 表示操作类型。那么上面那个例子就表示：

* `news.browse` 新闻模块的浏览权限
* `news.edit` 新闻模块的编辑权限

路由权限是比较暴力的，即没有权限则该路由页面无法访问，并且也不会在导航菜单中显示。但在实际业务中，遇到更多的情况通常是，可以访问路由页面，但会根据不同权限，使用页面里的不同功能，这时候就需要用到下面三种鉴权方式。

## 鉴权指令

对于单个元素，提供了 `v-auth` 指令。

```vue
<!-- 单权限验证 -->
<button v-auth="'department.create'">新增部门</button>

<!-- 多权限验证，用户只要具备其中任何一个权限，则验证通过 -->
<button v-auth="['department.create', 'department.edit']">新增部门</button>

<!-- 多权限验证，用户必须具备全部权限，才验证通过 -->
<button v-auth.all="['department.create', 'department.edit']">新增部门</button>
```

## 鉴权组件

页面中某个模块，当前用户具备该权限是如何显示，不具备该权限又是如何显示，针对这样的需求，框架提供了 `<AppAuth>` 组件。

```vue
<!-- 单权限验证 -->
<AppAuth :value="'department.create'">
  <p>你有该权限</p>
  <template #no-auth>
    <p>你没有该权限</p>
  </template>
</AppAuth>

<!-- 多权限验证，用户只要具备其中任何一个权限，则验证通过 -->
<AppAuth :value="['department.create', 'department.edit']">
  <p>你有该权限</p>
  <template #no-auth>
    <p>你没有该权限</p>
  </template>
</AppAuth>

<!-- 多权限验证，用户必须具备全部权限，才验证通过 -->
<AppAuth :value.all="['department.create', 'department.edit']">
  <p>你有该权限</p>
  <template #no-auth>
    <p>你没有该权限</p>
  </template>
</AppAuth>
```

## 鉴权函数

鉴权组件和鉴权指令控制的是页面上的元素，而鉴权函数则更多是使用在业务流程代码里的权限判断。

```ts
const { auth, authAll } = useAppAuth()

// 单权限验证，返回 true 或 false
auth('department.create')

// 多权限验证，用户只要具备其中任何一个权限，则验证通过，返回 true 或 false
auth(['department.create', 'department.edit'])

// 多权限验证，用户必须具备全部权限，才验证通过，返回 true 或 false
authAll(['department.create', 'department.edit'])
```

## 扩展阅读

由于权限配置不涉及角色，所以在实现上会更灵活，开发者可自行扩展出角色模块，根据不同角色动态设置该角色所拥有的权限，然后用户与角色挂钩，这样就无需繁琐的给每个用户重复配置权限。

当然针对一些小型的管理系统，对权限这块没有这么多复杂的要求，甚至什么角色拥有什么权限都是固定的，不需要自由配置。针对这种情况，框架也可以很方便的实现。

假设有 2 种角色，一个是管理员 `admin` ，一个是编辑员 `editor` ，如果用户是 `admin` 权限，则可以操作 Banner 管理下的所有功能，如果是 `editor` 权限，则只能进行新增 Banner 操作。

```ts {11,20,29,38}
import type { RouteRecordRaw } from 'vue-router'

const routes: RouteRecordRaw = {
  path: '/banner',
  component: () => import('@/layouts/index.vue'),
  redirect: '/banner/list',
  name: 'banner',
  meta: {
    title: 'Banner 管理',
    icon: 'banner',
    auth: ['admin', 'editor'], // 直接使用角色名当做权限验证字段
  },
  children: [
    {
      path: 'detail',
      name: 'bannerCreate',
      component: () => import('@/views/banner/detail.vue'),
      meta: {
        title: '新增 Banner',
        auth: ['admin', 'editor'],
      },
    },
    {
      path: 'list',
      name: 'bannerList',
      component: () => import('@/views/banner/list.vue'),
      meta: {
        title: 'Banner 列表',
        auth: ['admin'],
      },
    },
    {
      path: 'detail/:id',
      name: 'bannerEdit',
      component: () => import('@/views/banner/detail.vue'),
      meta: {
        title: '编辑 Banner',
        auth: ['admin'],
        menu: false,
      },
    },
  ],
}

export default routes
```
