当前位置: 首页 > article >正文

【vue项目权限控制方案】

文章目录

  • 后端控制权限
  • 模拟后端接口
  • 前端请求逻辑
    • 登陆
  • 前端路由和按钮权限控制

后端控制权限

思路:用户登录后可以获取到用户登陆的菜单,在跳转到下一个页面前,将获取到的用户的菜单格式化一下,以满足前端的规则,然后通过addRoute方法把新的路由加进去,然后记录路由规则的state,方便后续使用。

模拟后端接口

前端请求/routers接口时传入的用户id,后端返回相应的(该用户有权限的)页面,返回数据大概如下:
请添加图片描述
前端访问/login接口传入账户密码,然后返回相应的id,代码大概如下:
请添加图片描述

前端请求逻辑

route/index里面的路由规则是基本的路由规则,是不用登录也能访问的页面。perssion.js里面的路由规则需要登录才能访问,需要根据权限来判断能不能访问

登陆

将用户输入的账号密码传给后端,使用js-cookie库的Cookies.set将后端返回的token保存在cookie中,views/login.vue:

<template>
    <div class="home">
        <input v-model="username" />
        <input v-model="password" />
        <button @click="loginIn">登录</button>
    </div>
</template>
  
<script>
import axios from "axios"
import Cookies from 'js-cookie'

export default {
    name: 'login',
    data() {
        return {
            username: "",
            password: ""
        }
    },
    methods: {
        loginIn() {
            axios.post("http://localhost:3000/login",
                { username: this.username, password: this.password }).then((res) => {
                    if (res.data.token) {
                        Cookies.set('token', res.data.token);
                        Cookies.set('id', res.data.id);
                        this.$router.push("/");
                    }
                })
        }
    }
}
</script>  

建议将路由规则保存在store里,因为首页渲染菜单需要用到。
思路:在actions中发请求获取路由规则,然后解析并格式化路由规则,在mutation中修改路由。store/index.js:

import Vue from 'vue'
import Vuex from 'vuex'
import Cookies from 'js-cookie'
import { initRoutes, resetRouter } from "../router"
import axios from 'axios'
Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    asyncRoute: [],// 请求回来的路由
    routes: []// 所有的路由(初始路由+请求回来的路由)
  },
  mutations: {
    SET_ROUTES: (state, routes) => {
      state.asyncRoute = routes;
      state.routes = initRoutes.concat(routes);// 初始路由拼接请求回来的路由,获得完整路由
    },
    RESET_ROUTES: (state, routes) => {
      state.asyncRoute = [];
      state.routes = [];
    },
  },
  actions: {
    // 发请求获取路由规则,然后解析并格式化路由规则,返回出去供前端使用
    getRouter({ commit }) {
      // routeArr为路由规则数组,就是访问/routers得到的响应数组
      function parseRouter(routeArr) {
        let _newArr = [];
        routeArr.forEach((item) => {
          let _newItem = Object.assign({}, item);
          let _str = item.component;
          //"/page1.vue"=>import("@/views/page1.vue")
          //格式化规则
          _newItem.component = (resolve) => {
            //两个坑
            //return require([`@/views${_str}`],resolve)// 1. 有些低版本的webpack不能使用import,得用require
            return import(`@/views${_str}`)// 2. 这里必须用模版引擎,并且后端返回不能返回src/views,如果带上了,这里写`@${_str}`也会报错
          }
          _newArr.push(_newItem);
        })
        return _newArr
      }
      let _id = Cookies.get("id")
      if (_id) {
        return new Promise((resolve, reject) => {
          // 每次刷新页面都会发请求,所以每次路由跳转前先检查localStorage中有没有路由规则,有则直接使用,没有再发请求获取,并将请求到的路由规则保存在localStorage中
          let _local = JSON.parse(localStorage.getItem("menu"));
          if (_local) {
            let _newArr = parseRouter(_local);
            commit("SET_ROUTES", _newArr);
            resolve(_newArr)
          } else {
            axios.get("http://localhost:3000/routes?id=" + _id).then((res) => {
              let _newArr = parseRouter(res.data.data)
              localStorage.setItem("menu", JSON.stringify(res.data.data));
              commit("SET_ROUTES", _newArr);
              resolve(_newArr);
            })
          }

        })
      }
    },
    //按钮
    //登录-拉去一下用户的权限code ["some1","SOMETHING"]
    getCode() {

    },
    resetRouter({ commit }) {
      resetRouter();
      commit('RESET_ROUTES');
    }
  },
  modules: {
  }
})

router/index.js:

import Vue from 'vue'
import VueRouter from 'vue-router'
import Home from '../views/Home.vue'
import login from '../views/login.vue'
Vue.use(VueRouter)
export const initRoutes = [
  {
    path: '/',
    name: 'Home',
    component: Home,
    meta: {
      // 可以访问这个页面的用户,用户登陆后,前端可以通过登陆接口获取到用户,如果是admin/manger用户,在beforeEach中通过to.meta.whiteList判断当前用户有没有权限,
      // 如果有权限,to.next()
      whiteList: ["admin", "manger"]
    }
  },
  {
    path: '/about',
    name: 'About',
    // route level code-splitting
    // this generates a separate chunk (about.[hash].js) for this route
    // which is lazy-loaded when the route is visited.
    component: function () {
      return import(/* webpackChunkName: "about" */ '../views/About.vue')
    }
  },
  {
    path: '/login',
    name: 'login',
    component: login
  },
]

const router = new VueRouter({
  routes: initRoutes
})

// 重置路由规则:创建新的路由,把新路由的规则给老路由
export function resetRouter() {
  const newrouter = new VueRouter({
    routes: initRoutes
  })
  router.matcher = newrouter.matcher
}
export default router

权限控制页面perssion.js

import router from './router'
import store from './store'
import axios from "axios"
import Cookies from 'js-cookie'
//根据id请求接口获取规则
let whiteList = ["/about", "/login"]// 不需要登陆就可以访问的页面
// 因为store.dispatch("getRouter")会返回一个promise,需要await一下,等返回后再操作,所以这里得写成async函数
router.beforeEach(async (to, from, next) => {
    const token = Cookies.get("token");
    if (token) {
        if (to.path == "/login") {
            next("/");
        } else {
            //判断是不是已经请求拿了路由规则了
            if (store.state.asyncRoute.length == 0) {
                const _asyncRoutes = await store.dispatch("getRouter");// 获取到路由规则
                _asyncRoutes.forEach((item) => {
                    router.addRoute(item);//注册路由
                })
                //继续跳转
                next(to.path)
            } else {
                //没有page3 page4
                //user page1 page2 
                if (to.matched.length != 0) {// 要去的这个路由在路由规则中有没有匹配
                    next();
                } else {
                    alert("无页面权限")
                    next(from.path);
                }
            }
        }
    } else {
        if (whiteList.indexOf(to.path) != -1) {
            next()
        } else {
            next("/login")
        }
    }
})

登陆页:

<template>
    <div class="home">
        <input v-model="username" />
        <input v-model="password" />
        <button @click="loginIn">登录</button>
    </div>
</template>
  
<script>
import axios from "axios"
import Cookies from 'js-cookie'

export default {
    name: 'login',
    data() {
        return {
            username: "",
            password: ""
        }
    },
    methods: {
        loginIn() {
            axios.post("http://localhost:3000/login",
                { username: this.username, password: this.password }).then((res) => {
                    if (res.data.token) {
                        Cookies.set('token', res.data.token);
                        Cookies.set('id', res.data.id);
                        this.$router.push("/");
                    }
                })
        }
    }
}
</script>

登出页:

<template>
  <div class="home">
    <div v-for="item in $store.state.routes">
      <router-link :to="item.path">{{ item.name }}</router-link>
    </div>
    <button @click="loginout">登出</button>
  </div>
</template>

<script>
import Cookie from "js-cookie"
export default {
  name: 'home',
  created() {
  },
  methods: {
    loginout() {
      // 退出登陆时清空cookie,清空localStorage、store,清空路由,跳转到登陆页
      Cookie.remove("id");
      Cookie.remove("token");
      localStorage.removeItem("menu");
      this.$store.dispatch("resetRouter")
      this.$router.push("/login")
    }
  }
}
</script>

前端路由和按钮权限控制

按钮权限思路:登陆时拉取用户权限code,每个code都有对应的操作权限,如果按钮有某个操作权限,则展示,否则隐藏
路由思路:为路由定义meta属性,在其中定义whiteList对象,存放可以访问这个页面的用户,用户登陆后,前端可以通过登陆接口获取到用户,如果是admin/manger用户,在beforeEach中通过to.meta.whiteList判断当前用户有没有权限,如果有权限:to.next()

export const initRoutes = [
  {
    path: '/',
    name: 'Home',
    component: Home,
    meta: {
      // 可以访问这个页面的用户,用户登陆后,前端可以通过登陆接口获取到用户,如果是admin/manger用户,在beforeEach中通过to.meta.whiteList判断当前用户有没有权限,
      // 如果有权限,to.next()
      whiteList: ["admin", "manger"]
    }
  },
  ]

http://www.kler.cn/a/527946.html

相关文章:

  • Koa 基础篇(二)—— 路由与中间件
  • 数据库性能优化(sql优化)_SQL执行计划03_yxy
  • 论文阅读:Realistic Noise Synthesis with Diffusion Models
  • HTML<hgroup>标签
  • java+vue项目部署记录
  • 网络安全技术简介
  • Linux stat 命令使用详解
  • 内部知识库提升组织效率与知识共享助力业务快速发展
  • 开源的瓷砖式图像板系统Pinry
  • MySQL 插入数据
  • 【环境搭建】1.1源码下载与同步
  • 计算机网络之ISO/OSI参考模型和TCP/IP模型
  • 【4Day创客实践入门教程】Day0 创想启程——课程与项目预览
  • 【Qt5】声明之后快速跳转
  • WPS mathtype间距太大、显示不全、公式一键改格式/大小
  • 三次方根pow
  • Python 列表思维导图
  • 使用Pygame制作“太空侵略者”游戏
  • (即插即用模块-特征处理部分) 十九、(NeurIPS 2023) Prompt Block 提示生成 / 交互模块
  • leetcode 844 比较含退格的字符串
  • 利用 AMD Instinct™ MI300X 提升计算流体动力学性能
  • cf1000(div.2)
  • 微服务实战 原生态实现服务的发现与调用_如何发现应用的服务调用问题
  • 从 UTC 日期时间字符串获取 Unix 时间戳:C 和 C++ 中的挑战与解决方案
  • P1158
  • 19 压测和常用的接口优化方案