• vue路由登录拦截(vue router登录权限控制)


    实现原理:

    /:指向组件App.vue,它是最外层组件,下面的/login和/main对应的组件都会包含在其中;

    /login:指向登录组件Login.vue;

    /main:指向登录后组件Main.vue,其下会包括很多子组件来展示不同菜单项。

    用户有没有登录需要给其指定状态(用islogin表示),当用户登录了,我们用localStorage在Login.vue文件中为其状态设定为1:

    methods: {
          submitForm(formName) {
            let _this = this;
            let param = new URLSearchParams();
            param.append('username', _this.ruleForm.username);
            param.append('password', _this.ruleForm.password);
    
            this.$refs[formName].validate((valid) => {
              if (valid) {
                _this.$axios({
                  method: 'POST',
                  url: '/api/blog/check_login_status/',
                  data: param
                })
                .then(res => {
                  if(res.data.ret){
                    localStorage.setItem("islogin", 1);
                    console.log(localStorage.getItem("islogin"));
                    _this.$router.push({path: "/main/form/radio"});
                  }else{
                    _this.$message('用户名或密码错误!');
                    return false;
                  }
                })
                .catch(err => {
                  console.log(err);
                });
              } else {
                console.log('error submit!!');
                return false;
              }
            });
          },
          resetForm(formName) {
            this.$refs[formName].resetFields();
          }
        }

    这里可能会有Django后台获取不到前端axios-post请求提交的参数的问题,方法请参考:

    https://blog.csdn.net/duansamve/article/details/101942106

    退出时需要为其指定状态为0:

    localStorage.setItem("islogin", 0);

    路由拦截需要用到导航守卫,关键代码如下:

    router.beforeEach((to, from, next) => {
      let islogin = localStorage.getItem("islogin");
      islogin = Boolean(Number(islogin));
    
      if(to.path == "/login"){
        if(islogin){
          next("/table");
        }else{
          next();
        }
      }else{
        // requireAuth:可以在路由元信息指定哪些页面需要登录权限
        if(to.meta.requireAuth && islogin) {
          next();
        }else{
          next("/login");
        }
      }
    })

    src/router/index.js中,可以看到所有路由如下:

    let router = new Router({
      mode: 'hash',
      routes: [
        {
          path: '/',
          name: 'index',
          redirect: '/login'
        },
        {
          path: '/login',
          name: 'Login',
          component: Login,
          meta: {
            title: 'Login',
            icon: 'el-icon-eleme',
            requireAuth: true
          }
        },
        {
          path: '/main',
          name: 'main',
          component: Main,
          show: false,
          meta: {
            title: 'Main',
            icon: 'el-icon-eleme',
            requireAuth: true
          },
          children: [
            {
              path: '/main/form/radio',
              name: 'radio',
              component: Radio,
              show: true,
              meta: {
                title: 'Radio',
                icon: 'el-icon-s-marketing',
                requireAuth: true
              }
            },
            {
              path: '/main/form/checkbox',
              name: 'checkbox',
              component: Checkbox,
              show: true,
              meta: {
                title: 'Checkbox',
                icon: 'el-icon-s-marketing',
                requireAuth: true
              }
            },
            {
              path: '/main/data/table',
              name: 'table',
              component: Table,
              show: true,
              meta: {
                title: 'Table',
                icon: 'el-icon-s-marketing',
                requireAuth: true
              }
            },
            {
              path: '/main/data/tag',
              name: 'tag',
              component: Tag,
              show: true,
              meta: {
                title: 'Tag',
                icon: 'el-icon-s-marketing',
                requireAuth: true
              }
            },
            {
              path: '/main/button',
              name: 'button',
              component: Button,
              show: true,
              meta: {
                title: 'Button',
                icon: 'el-icon-s-order',
                requireAuth: true
              }
            },
            {
              path: '/main/tabs',
              name: 'tabs',
              component: Tabs,
              show: true,
              meta: {
                title: 'Tabs',
                icon: 'el-icon-s-ticket',
                requireAuth: true
              }
            },
            {
              path: '/main/echarts',
              name: 'echarts',
              component: Echarts,
              show: true,
              meta: {
                title: 'Echarts',
                icon: 'el-icon-s-marketing',
                requireAuth: true
              }
            }
          ]
        }
      ]
    });

    我们只需要把/main的子路由在菜单中循环出来,其它不需要显示,所以在Main.vue中增加如下方法提取/main的所有子路由:

      methods: {
        getRoutes() {
          for (let i = 0; i < this.$router.options.routes.length; i++) {
            if (this.$router.options.routes[i].name === "main") {
              return this.$router.options.routes[i].children;
            }
          }
        }
      }

    关键文件代码:

    router/index.js:

    import Vue from 'vue'
    import Router from 'vue-router'
    import Login from '@/components/Login'
    import Main from '@/components/Main'
    import Radio from '@/components/Radio'
    import Checkbox from '@/components/Checkbox'
    import Table from '@/components/Table'
    import Tag from '@/components/Tag'
    import Button from '@/components/Button'
    import Tabs from '@/components/Tabs'
    import Echarts from '@/components/Echarts'
    
    Vue.use(Router);
    
    let router = new Router({
      mode: 'hash',
      routes: [
        {
          path: '/',
          name: 'index',
          redirect: '/login'
        },
        {
          path: '/login',
          name: 'Login',
          component: Login,
          meta: {
            title: 'Login',
            icon: 'el-icon-eleme',
            requireAuth: true
          }
        },
        {
          path: '/main',
          name: 'main',
          component: Main,
          show: false,
          meta: {
            title: 'Main',
            icon: 'el-icon-eleme',
            requireAuth: true
          },
          children: [
            {
              path: '/main/form/radio',
              name: 'radio',
              component: Radio,
              show: true,
              meta: {
                title: 'Radio',
                icon: 'el-icon-s-marketing',
                requireAuth: true
              }
            },
            {
              path: '/main/form/checkbox',
              name: 'checkbox',
              component: Checkbox,
              show: true,
              meta: {
                title: 'Checkbox',
                icon: 'el-icon-s-marketing',
                requireAuth: true
              }
            },
            {
              path: '/main/data/table',
              name: 'table',
              component: Table,
              show: true,
              meta: {
                title: 'Table',
                icon: 'el-icon-s-marketing',
                requireAuth: true
              }
            },
            {
              path: '/main/data/tag',
              name: 'tag',
              component: Tag,
              show: true,
              meta: {
                title: 'Tag',
                icon: 'el-icon-s-marketing',
                requireAuth: true
              }
            },
            {
              path: '/main/button',
              name: 'button',
              component: Button,
              show: true,
              meta: {
                title: 'Button',
                icon: 'el-icon-s-order',
                requireAuth: true
              }
            },
            {
              path: '/main/tabs',
              name: 'tabs',
              component: Tabs,
              show: true,
              meta: {
                title: 'Tabs',
                icon: 'el-icon-s-ticket',
                requireAuth: true
              }
            },
            {
              path: '/main/echarts',
              name: 'echarts',
              component: Echarts,
              show: true,
              meta: {
                title: 'Echarts',
                icon: 'el-icon-s-marketing',
                requireAuth: true
              }
            }
          ]
        }
      ]
    });
    
    export default router
    
    router.beforeEach((to, from, next) => {
      let islogin = localStorage.getItem("islogin");
      console.log(islogin);
      console.log(to.path);
      islogin = Boolean(Number(islogin));
     
      if(to.path == "/login"){
        if(islogin){
          next("/main/form/radio");
        }else{
          next();
        }
      }else{
        // requireAuth:可以在路由元信息指定哪些页面需要登录权限
        if(to.meta.requireAuth && islogin) {
          next();
        }else{
          next("/login");
        }
      }
    })

    Login.vue:

    <template>
      <div id="login-container">
        <el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="demo-ruleForm">
          <el-form-item label="用户名" prop="checkUser">
            <el-input type="text" v-model="ruleForm.username" autocomplete="off"></el-input>
          </el-form-item>
          <el-form-item label="密码" prop="checkPass">
            <el-input type="password" v-model="ruleForm.password" autocomplete="off"></el-input>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" @click="submitForm('ruleForm')">提交</el-button>
            <el-button @click="resetForm('ruleForm')">重置</el-button>
          </el-form-item>
        </el-form>
      </div>
    </template>
     
    <script>
      export default {
        name: 'Login',
        components: {
     
        },
        data() {
          var validateUser = (rule, value, callback) => {
            if (value === '') {
              callback(new Error('请输入用户名'));
            }  else {
              callback();
            }
          };
    
          var validatePass = (rule, value, callback) => {
            if (value === '') {
              callback(new Error('请输入密码'));
            } else {
              callback();
            }
          };
    
          return {
            ruleForm: {
              username: '',
              password: ''
            },
            rules: {
              checkUser: [
                { validator: validateUser, trigger: 'blur' }
              ],
              checkPass: [
                { validator: validatePass, trigger: 'blur' }
              ]
            }
          };
        },
        methods: {
          submitForm(formName) {
            let _this = this;
            let param = new URLSearchParams();
            param.append('username', _this.ruleForm.username);
            param.append('password', _this.ruleForm.password);
    
            this.$refs[formName].validate((valid) => {
              if (valid) {
                _this.$axios({
                  method: 'POST',
                  url: '/api/blog/check_login_status/',
                  data: param
                })
                .then(res => {
                  if(res.data.ret){
                    localStorage.setItem("islogin", 1);
                    console.log(localStorage.getItem("islogin"));
                    _this.$router.push({path: "/main/form/radio"});
                  }else{
                    _this.$message('用户名或密码错误!');
                    return false;
                  }
                })
                .catch(err => {
                  console.log(err);
                });
              } else {
                console.log('error submit!!');
                return false;
              }
            });
          },
          resetForm(formName) {
            this.$refs[formName].resetFields();
          }
        }
      }
    </script>
     
    <style scoped>
      body{
        margin: 0;
      }
      #login-container{
         400px;
        height: 300px;
        background: #e5e9f2;
        position: absolute;
        left: 50%;
        top: 50%;
        margin-left: -220px;
        margin-top: -170px;
        border-radius: 5px;
        padding-top: 40px;
        padding-right: 40px;
      }
    </style>

    Main.vue:

    
    <template>
      <div id="app">
        <el-container style="height: 100%;">
          <el-header style="height: 80px;" :style="topBg">
            <Header/>
          </el-header>
          <el-container>
            <el-aside width="210px" :style="leftBg">
              <el-row class="tac">
                <el-col :span="24">
                  <el-menu
                    default-active="2"
                    class="el-menu-vertical-demo"
                    @open="handleOpen"
                    @close="handleClose"
                  >
                    <template v-for="route in getRoutes()">
                        
                      <el-submenu
                        :key="route.path"
                        :index="route.path"
                        v-if="route.children && route.children.length"
                      >
    
                      <!-- 循环有子目录的菜单 -->
                        <template slot="title">
                          <i :class="route.meta.icon"></i>
                          <span>{{route.meta.title}}</span>
                        </template>
                        <el-menu-item-group>
                          <router-link :to="todo.path" :key="todo.path" v-for="todo in route.children">
                            <el-menu-item
                              :index="todo.path"
                            >{{todo.meta.title}}</el-menu-item>
                          </router-link>
                        </el-menu-item-group>
                      </el-submenu>
     
                      <!-- 循环没有子目录的菜单 -->
                      <router-link
                        :to="route.path"
                        :key="route.path"
                        v-else-if="!route.children && route.path != '/' && route.path != '/login'"
                      >
                        <el-menu-item :index="route.path">
                          <i :class="route.meta.icon"></i>
                          <span>{{route.meta.title}}</span>
                        </el-menu-item>
                      </router-link>
    
                    </template>
                  </el-menu>
                </el-col>
              </el-row>
            </el-aside>
            <el-main>
              <router-view></router-view>
            </el-main>
          </el-container>
        </el-container>
      </div>
    </template>
     
    <script>
    import Header from '@/components/Header'
    export default {
      name: "App",
      data() {
        return {
          leftBg: {
            background: "#235d8b url(" + require("../assets/left-bg.png") + ") no-repeat scroll 0 bottom"
          },
          topBg: {
            background: "#235d8b url(" + require("../assets/top-bg.png") + ") no-repeat scroll right 0",
            height: '80px',
            fontSize: '32px',
            color: '#ffffff'
          }
        }
      },
      components: {
        Header
      },
      methods: {
        handleOpen(key, keyPath) {
          console.log(key, keyPath);
        },
        handleClose(key, keyPath) {
          console.log(key, keyPath);
        },
        getRoutes() {
          for (let i = 0; i < this.$router.options.routes.length; i++) {
            if (this.$router.options.routes[i].name === "main") {
              return this.$router.options.routes[i].children;
            }
          }
        }
      }
    };
    </script>
     
    <style>
    #app {
      font-family: "Avenir", Helvetica, Arial, sans-serif;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      color: #2c3e50;
      height: 100%;
    }
     
    .el-header,
    .el-footer {
      background-color: #b3c0d1;
      color: #333;
      line-height: 80px;
    }
     
    .el-aside {
      background-color: #d3dce6;
      color: #333;
    }
     
    .el-aside a{
      text-decoration: none;
    }
    
    .el-menu {
      background: none;
    }
     
    .el-main {
      background-color: #ffffff;
      color: #333;
    }
     
    body > .el-container {
      margin-bottom: 40px;
    }
     
    .el-container:nth-child(5) .el-aside,
    .el-container:nth-child(6) .el-aside {
      line-height: 260px;
    }
     
    .el-container:nth-child(7) .el-aside {
      line-height: 320px;
    }
    </style>

    django代码:views.py

    @csrf_exempt
    def check_login_status(request):
        return_dict = {"ret": False}
    
        if request.method == "POST":
            username = request.POST.get('username')
            password = request.POST.get('password')
            if username == 'admin' and password == '123456':
                return_dict['ret'] = True
    
        return HttpResponse(json.dumps(return_dict), content_type="application/json")

    vue从django跨域获取数据请参考博文:https://blog.csdn.net/duansamve/article/details/90310911

  • 相关阅读:
    Android NDK 开发中 adb logcat 命令的使用
    android 工程里缺少 R.java 文件原因和解决方法
    用Linux命令行实现删除和复制指定类型的文件
    重载操作符与转换
    复制控制
    管理类的指针成员
    复制构造函数
    static类成员(变量和函数)
    lock failed, MQ already started 问题处理
    Mac无法启动RocketMQ,日志显示,runserver.sh: line 91: /Library/Internet: No such file or directory
  • 原文地址:https://www.cnblogs.com/samve/p/11619928.html
Copyright © 2020-2023  润新知