Vue 3中的权限控制:基于角色的访问控制实现

2025-04发布6次浏览

在Vue 3应用中实现基于角色的访问控制(Role-Based Access Control, RBAC),是一种常见的权限管理方式。通过这种方式,我们可以确保用户只能访问与其角色相对应的功能或页面。以下将详细介绍如何在Vue 3项目中实现这一功能。

基本概念

RBAC的核心思想是根据用户的“角色”来决定其可以访问的资源或执行的操作。例如,管理员可以访问所有页面和功能,而普通用户可能只能访问部分页面。在实现时,通常需要结合路由守卫、Vuex状态管理以及后端API接口来完成。


1. 环境准备

首先确保你的Vue 3项目已经创建好,并安装了vue-routerpinia(或者vuex)。如果尚未安装,可以通过以下命令安装:

npm install vue-router pinia

2. 后端返回用户角色

假设后端提供了一个登录接口,登录成功后会返回用户的token及角色信息。示例返回数据如下:

{
  "token": "your_jwt_token",
  "role": "admin" // 或者 "user"
}

我们需要在前端存储这些信息以便后续使用。


3. 使用Pinia管理用户状态

创建一个Pinia store来保存用户的登录状态和角色信息。

// stores/user.js
import { defineStore } from 'pinia';

export const useUserStore = defineStore('user', {
  state: () => ({
    token: null,
    role: null,
  }),
  actions: {
    setToken(token) {
      this.token = token;
    },
    setRole(role) {
      this.role = role;
    },
    logout() {
      this.token = null;
      this.role = null;
    },
  },
});

在登录逻辑中,调用此store来保存用户信息。


4. 配置路由

vue-router中定义多个页面,并为每个页面设置允许访问的角色。

// router/index.js
import { createRouter, createWebHistory } from 'vue-router';
import Home from '../views/Home.vue';
import AdminDashboard from '../views/AdminDashboard.vue';
import UserDashboard from '../views/UserDashboard.vue';

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home,
    meta: { roles: ['admin', 'user'] }, // 所有用户都可以访问
  },
  {
    path: '/admin',
    name: 'AdminDashboard',
    component: AdminDashboard,
    meta: { roles: ['admin'] }, // 只有管理员可以访问
  },
  {
    path: '/user',
    name: 'UserDashboard',
    component: UserDashboard,
    meta: { roles: ['user'] }, // 只有普通用户可以访问
  },
];

const router = createRouter({
  history: createWebHistory(),
  routes,
});

export default router;

5. 实现路由守卫

通过路由守卫检查当前用户的角色是否符合目标页面的要求。

// main.js
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import { useUserStore } from './stores/user';

const app = createApp(App);

app.use(router);

router.beforeEach((to, from, next) => {
  const userStore = useUserStore();
  
  if (to.meta.roles) {
    // 检查用户是否有权限访问目标页面
    if (!to.meta.roles.includes(userStore.role)) {
      alert('您没有权限访问该页面');
      return next('/');
    }
  }

  next();
});

app.mount('#app');

6. 登录逻辑

在登录页面中,调用后端接口获取用户信息,并将其保存到Pinia store中。

// views/Login.vue
<template>
  <div>
    <input v-model="username" placeholder="用户名" />
    <input v-model="password" type="password" placeholder="密码" />
    <button @click="login">登录</button>
  </div>
</template>

<script>
import { ref } from 'vue';
import axios from 'axios';
import { useRouter } from 'vue-router';
import { useUserStore } from '../stores/user';

export default {
  setup() {
    const username = ref('');
    const password = ref('');
    const router = useRouter();
    const userStore = useUserStore();

    const login = async () => {
      try {
        const response = await axios.post('/api/login', {
          username: username.value,
          password: password.value,
        });

        const { token, role } = response.data;

        // 保存用户信息
        userStore.setToken(token);
        userStore.setRole(role);

        // 跳转到首页
        router.push('/');
      } catch (error) {
        console.error(error);
        alert('登录失败,请检查用户名和密码');
      }
    };

    return { username, password, login };
  },
};
</script>

7. 权限控制的扩展

动态路由加载

如果某些页面的显示取决于用户的权限,可以在登录成功后动态添加路由:

function addDynamicRoutes(routes, userRole) {
  if (userRole === 'admin') {
    routes.push({
      path: '/settings',
      name: 'Settings',
      component: () => import('@/views/Settings.vue'),
      meta: { roles: ['admin'] },
    });
  }
}

然后在登录成功后调用此函数更新路由表。

组件级权限控制

除了路由级别的权限控制,还可以在组件内进行更细粒度的权限检查。例如,隐藏某些按钮或菜单项。

<template>
  <div>
    <button v-if="isAdmin">管理功能</button>
  </div>
</template>

<script>
import { computed } from 'vue';
import { useUserStore } from '@/stores/user';

export default {
  setup() {
    const userStore = useUserStore();
    const isAdmin = computed(() => userStore.role === 'admin');

    return { isAdmin };
  },
};
</script>

8. 流程图

以下是整个权限控制流程的Mermaid代码表示:

sequenceDiagram
    participant User
    participant Vue
    participant Backend
    User->>Vue: 输入用户名和密码
    Vue->>Backend: 发送登录请求
    Backend-->>Vue: 返回token和角色
    Vue->>Vue: 存储token和角色
    Vue->>Vue: 检查路由权限
    alt 有权限
        Vue-->>User: 跳转到目标页面
    else 无权限
        Vue-->>User: 提示无权限并跳转到首页
    end