Vue用户登录角色鉴权,不同用户登录展示不同的菜单导航。

1 篇文章 0 订阅

效果展示

登录页面

user登录

admin登录

实现原理

前端请求API接口后台根据登录不同的用户返回相应的菜单格式,前端存储到Vuex中,router定义所有的路由,在路由中判断请求过来的菜单数据跟router中定义的路由进行对比,相同则动态添加到路由中。

src目录展示

src目录中各目录代码

mock/index.vue

  • mock安装:
  1. npm install mockjs
  2. main.js中引入mock
  •  代码展示:
import mockJS from 'mockjs';
const users = [
    {
        id: 1,
        username: 'user',
        password: '123456',
        token: 'userToken',
        role: 'user',
    },
    {
        id: 2,
        username: 'admin',
        password: '123456',
        token: 'adminToken',
        role: 'admin',
    }
]
const roles = {
    user: [
        {
            id:'1',
            authName:"user 1",
            path:'home'
        },
        {
            id:'2',
            authName:"user 2",
            path:'home2'
        },
        {
            id:'3',
            authName:"user 3",
            path:'home3'
        },
    ],
    admin: [
        {
            id:'1',
            authName: '高级菜单',
            children: [
                {
                    id:'11',
                    authName: 'admin 1',
                    path: 'admin',
                },
                {
                    id:'12',
                    authName: 'admin 2',
                    path: 'admin2',
                }
            ]
        },

        {
            id:'2',
            authName:"admin 3",
            path:'admin3'
        },
    ]
}


// 用户登录
mockJS.mock('/login', 'post', option => {
    const { username, password } = JSON.parse(option.body)
    const user = users.find(item => {
        return item.username === username && item.password === password
    })
    return user
})

// 用户权限信息
mockJS.mock('/roles', 'post', option => {
    const {name}=JSON.parse(option.body)
    // console.log(option.body);
    // console.log(JSON.parse(option.body));
    console.log(name);
    return roles[name]
})

 router/index.vue

import Vue from "vue";
import VueRouter from "vue-router";
import store from '../store'
Vue.use(VueRouter);

const routes = [
  {
    path: "/",
    redirect: "/index",
    component: () => import("@/views/layout"),
    children: [
      {
        path:'/index',
        component:()=>import('@/views/index')
      }
    ],
  },
  {
    path: "/login",
    component: () => import("@/views/login"),
  },
];
//定义所需的所有路由
const home = {
  path:'/home',
  component:()=>import('@/views/home')
}
const home2={
  path:'/home2',
  component:()=>import('@/views/home2')
}
const home3={
  path:'/home3',
  component:()=>import('@/views/home3')
}
const admin={
  path:'/admin',
  component:()=>import('@/views/admin')
}
const admin2={
  path:'/admin2',
  component:()=>import('@/views/admin2')
}
const admin3={
  path:'/admin3',
  component:()=>import('@/views/admin3')
}

const ruleList = {
  home,home2,home3,admin,admin2,admin3
}
//定义动态添加路由的方法
export function initRoutes() {
  const currentRoutes = router.options.routes
  const menuList = store.state.list
  menuList.forEach(item=>{
    if(item.children){
      item.children.forEach(key=>{
        if(key.path){
          currentRoutes[0].children.push(ruleList[key.path])
        }
        console.log(ruleList[key.path]);
      })
    }else{
      if(item.path){
        currentRoutes[0].children.push(ruleList[item.path])
      }
    }
  })
  //便利当前路由动态添加
  for(let i=0,length=currentRoutes.length;i<length;i+=1){
    const element=currentRoutes[i]
    router.addRoute(element)
  }

}

const router = new VueRouter({
  mode: "history",
  base: process.env.BASE_URL,
  routes,
});

//前置路由守卫
router.beforeEach((to,from,next)=>{
  if(to.path === '/login'){
    next()
  }else{
    let token = sessionStorage.getItem('token')
    if(!token){
      next('/login')
    }else{
      next()
    }
  }
})
export default router;

store/index.vue

  • Vuex刷新防止数据丢失
  1. 安装 vuex-persistedstate
    npm install --save vuex-persistedstate
  2.  配置
    import Vue from 'vue'
    import Vuex from 'vuex'
    //1.引入vuex-persistedstate
    import createPersistedState from "vuex-persistedstate";
    Vue.use(Vuex)
    
    export default new Vuex.Store({
      state: { 
      },
      getters: {
      },
      mutations: {
      },
      actions: {
      },
      modules: {
      },
    //2.配置项
      plugins: [createPersistedState()]
    })
    
  • 代码展示
import Vue from 'vue'
import Vuex from 'vuex'
import createPersistedState from "vuex-persistedstate";
Vue.use(Vuex)
export default new Vuex.Store({
  state: {
      user:{},
      list:[],
  },
  getters: {
  },
  mutations: {
    setUser(state,value){
      state.user=value
    },
    setList(state,value){
      state.list=value
    },
  },
  actions: {
  },
  modules: {
  },
  plugins: [createPersistedState()]
})

views各页面展示

admin,home,index/index.vue

页面一样展示的数据不同

<template>
    <div>
        <h2>home</h2>
        {{ $store.state.user }}
    </div>
</template>

<script>
export default {

}
</script>

<style></style>

layout/index.vue

<template>
  <el-container>
    <el-aside width="200px">
      <el-row class="tac">
        <el-col :span="12">
          <el-menu default-active="2" class="el-menu-vertical-demo" router>
            <el-menu-item index="/index">
              <i class="el-icon-menu"></i>
              <span slot="title">index</span>
            </el-menu-item>

            <!-- 遍历菜单 -->
            <template v-for="item in menuList">
              <!-- 含有子菜单 -->
              <template v-if="item.children && item.children.length > 0">
                <el-submenu
                  :index="item.id"
                  :key="item.id"
                >
                  <template slot="title">
                    <i class="el-icon-location"></i>
                    <span>{{ item.authName }}</span>
                  </template>

                  <el-menu-item
                    :index="'/' + subItem.path"
                    v-for="subItem in item.children"
                    :key="subItem.index"
                  >
                    <template>
                      <span>{{ subItem.authName }}</span>
                    </template>
                  </el-menu-item>
                </el-submenu>
              </template>
              <!-- 不含有子菜单 -->
              <template v-else>
                <el-menu-item :index="item.path" :key="item.id">
                  <i :class="item.icon"></i>
                  <span slot="title">{{ item.authName }}</span>
                </el-menu-item>
            </template>
            </template>
          </el-menu>
        </el-col>
      </el-row>
    </el-aside>
    <el-container>
      <el-header
        >Header
        <el-button @click="exit">exit</el-button>
      </el-header>
      <el-main>
        <router-view></router-view>
      </el-main>
    </el-container>
  </el-container>
</template>

<script>
import { mapState } from "vuex";
import { initDyamicRoutes } from "@/router";
export default {
  name: "Layout",
  data() {
    return {
      menuList: [],
    };
  },
  computed: {
    ...mapState(["list", "user"]),
  },
  created() {
    initDyamicRoutes();
    this.menuList = this.list;
  },
  methods: {
    exit() {
      this.$store.commit("setList", []);
      this.$store.commit("setUser", {});
      sessionStorage.removeItem('token')
      this.$router.push("/login");
    },
  },
};
</script>

<style>
/* ------------  Container 布局容器 全铺 -----------*/
.el-container {
  height: 100vh;
}

.el-row,
.el-col {
  height: 100%;
}

/*   ----------------------------------------- */
.el-header,
.el-footer {
  background-color: #b3c0d1;
}

.el-aside {
  background-color: #d3dce6;
}

.el-main {
  background-color: #e9eef3;
}

.el-menu-vertical-demo:not(.el-menu--collapse) {
  width: 200px;
  min-height: 100%;
}
</style>

login/index.vue

  • 页面展示

  • 代码展示
<template>
  <div>
    <h2>login</h2>
    <el-button @click="userBtn">mock test user login</el-button>
    <el-button @click="adminBtn">mock test admin login</el-button>
  </div>
</template>

<script>
import axios from 'axios'
export default {
  name: "home",
  data() {
    return {
      username:'',
      password:'123456'
    };
  },
  methods:{
    userBtn(){
      this.username='user',
      this.mockTestFn()
    },
    adminBtn(){
      this.username='admin',
      this.mockTestFn()
    },
    mockTestFn(){
        this.axios({
            method:'POST',
            url:'/login',
            data:{
                username:this.username,
                password:this.password
            }
        }).then(
            res=>{
                if(res.status==200){
                    this.$store.commit('setUser',res.data)
                   sessionStorage.setItem('token',res.data.token)
                    this.axios({
                      method:'POST',
                      url:'/roles',
                      data:{
                       name: res.data.role
                      }
                    }).then(
                      res=>{
                        console.log(res);
                        this.$store.commit('setList',res.data)
                        this.$message('success')
                        this.$router.push('/index')
                      }
                    )
                }
            }
        )
    }
  }
};
</script>

<style></style>

  • 0
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值