Роли и разрешения в meta

В Vue Router объект meta предназначен для хранения произвольных данных маршрута, которые могут использоваться на этапе навигации или внутри компонентов для управления доступом, отображением или поведением маршрута. Одним из ключевых сценариев применения meta является реализация ролей и разрешений пользователей, что позволяет гибко управлять доступом к различным частям приложения.

Структура маршрута с meta

Каждый маршрут может содержать объект meta, в котором можно хранить массив разрешённых ролей или другие данные, необходимые для контроля доступа. Например:

const routes = [
  {
    path: '/admin',
    component: AdminDashboard,
    meta: {
      requiresAuth: true,
      roles: ['admin', 'superuser']
    }
  },
  {
    path: '/profile',
    component: UserProfile,
    meta: {
      requiresAuth: true,
      roles: ['user', 'admin', 'superuser']
    }
  },
  {
    path: '/login',
    component: LoginPage,
    meta: {
      requiresAuth: false
    }
  }
];

Ключевые моменты:

  • requiresAuth указывает, что маршрут доступен только авторизованным пользователям.
  • roles содержит массив ролей, которые имеют доступ к маршруту.
  • meta доступен как в глобальных навигационных охранниках, так и в локальных компонентах через this.$route.meta.

Проверка ролей через глобальный охранник

Для контроля доступа используется глобальный навигационный охранник beforeEach. В нём можно проверять авторизацию пользователя и наличие соответствующей роли:

router.beforeEach((to, from, next) => {
  const user = getCurrentUser(); // Получение текущего пользователя
  const requiresAuth = to.meta.requiresAuth;
  const allowedRoles = to.meta.roles || [];

  if (requiresAuth && !user) {
    next('/login');
  } else if (allowedRoles.length && !allowedRoles.includes(user.role)) {
    next('/unauthorized');
  } else {
    next();
  }
});

Разбор логики:

  1. Если маршрут требует авторизации (requiresAuth) и пользователь не вошёл, выполняется редирект на страницу логина.
  2. Если маршрут содержит список разрешённых ролей (roles), проверяется, есть ли роль пользователя в этом списке. Если нет, выполняется редирект на страницу с ошибкой доступа.
  3. В остальных случаях навигация продолжается.

Вложенные маршруты и наследование meta

meta не наследуется автоматически в Vue Router. Для вложенных маршрутов можно реализовать проверку, проходя по всему маршруту и проверяя каждый уровень:

router.beforeEach((to, from, next) => {
  const user = getCurrentUser();
  const matchedRoutes = to.matched; // Массив всех маршрутов, совпавших с адресом
  const requiresAuth = matchedRoutes.some(r => r.meta.requiresAuth);
  const allowedRoles = matchedRoutes
    .filter(r => r.meta.roles)
    .map(r => r.meta.roles)
    .flat();

  if (requiresAuth && !user) {
    next('/login');
  } else if (allowedRoles.length && !allowedRoles.includes(user.role)) {
    next('/unauthorized');
  } else {
    next();
  }
});

Особенности:

  • to.matched содержит массив всех маршрутов, от родительского до конечного дочернего.
  • Использование flat() объединяет все массивы ролей в один.
  • Позволяет реализовать комплексную проверку для многоуровневых меню и разделов приложения.

Использование meta внутри компонентов

В компоненте можно использовать this.$route.meta для динамического отображения элементов интерфейса в зависимости от роли пользователя:

<template>
  <div>
    <button v-if="canEdit">Редактировать</button>
    <p v-if="!canView">Доступ ограничен</p>
  </div>
</template>

<script>
export default {
  computed: {
    canEdit() {
      const roles = this.$route.meta.roles || [];
      return roles.includes(this.$store.state.user.role);
    },
    canView() {
      return this.canEdit || this.$route.meta.requiresAuth === false;
    }
  }
}
</script>

Преимущества:

  • Возможность скрывать или показывать элементы интерфейса без изменения маршрутов.
  • Локальный контроль доступа, независимый от глобальных охранников.

Динамические маршруты и роли

В некоторых приложениях роли могут определять доступность маршрутов, и маршруты могут добавляться динамически после авторизации:

const dynamicRoutes = [
  {
    path: '/reports',
    component: ReportsPage,
    meta: { requiresAuth: true, roles: ['manager', 'admin'] }
  }
];

if (user.isAuthenticated) {
  dynamicRoutes.forEach(route => router.addRoute(route));
}
  • router.addRoute позволяет регистрировать маршруты после инициализации приложения.
  • Динамические маршруты позволяют строить интерфейс на основе прав пользователя, не раскрывая скрытые разделы приложения другим ролям.

Практические рекомендации

  • Использовать meta.roles только для проверки доступа. Для других целей (например, хлебные крошки или заголовки страниц) лучше заводить отдельные поля.
  • Всегда проверять все уровни вложенности через to.matched.
  • Совмещать проверку ролей с проверкой авторизации, чтобы исключить несанкционированный доступ.
  • При сложной логике доступа рекомендуется выносить проверку в отдельный модуль или сервис.

Роли и разрешения через meta обеспечивают гибкость и централизованный контроль доступа, позволяя эффективно управлять безопасностью интерфейса и навигацией в приложениях на Vue.