zoukankan      html  css  js  c++  java
  • vue项目中的登录鉴权

      用vue做一个简单的登录鉴权功能。

    项目目录结构如下:

    Login 组件

      登录成功后做本地存储和store存储,并进行跳转。

    Login.vue关键代码:

        async handleLogin(e) {
          e.preventDefault();
          let parmas = {
            username: this.model.username,
            passwold: this.model.passwold
          };
          const res = await this.$http.get("/api/login", parmas);
          const { code, token, massage } = res.data;
          //code=='0'表示登录成功,进行本地存储和store存储 并进行跳转。
          //else 弹出错误提示
          if (code == "0") {
            this.$store.commit("setToken", res.data.token);
            localStorage.setItem("token", token);
            //如果是由需要鉴权的页面跳转到登录页面 则redirect= this.$route.query.redirect,如果是直接点击登录跳转到登录页面,则redirect= '/'
            const redirect = this.$route.query.redirect || "/";
            this.$router.push(redirect);
          } else {
            const toast = this.$createToast({
              time: 2000,
              txt: massage || "登录失败",
              type: "error"
            });
            toast.show();
          }
        }

    store

      在Login组件里登录时token做了数据持久化处理,防止页面刷新丢失token。给store里的token赋初值的时候要取

    store.js关键代码:

    import Vue from 'vue'
    import Vuex from 'vuex'
    
    Vue.use(Vuex)
    
    export default new Vuex.Store({
      state: {
        //token数据持久化,防止页面刷新丢失
        token: localStorage.getItem('token') || ''
      },
      mutations: {
        setToken(state, token) {
          state.token = token
        }
      },
      actions: {
    
      },
      getters: {
        //根据token是否存在,设置计算属性isLogin
        isLogin(state) {
          return !!state.token
        }
      }
    })

    router

      routes[]里用 mate.auth来标识是否需要鉴权。router.beforeEach做个全局路由守卫,根据是否需要鉴权以及是否已经登录来进行不同操作。

    router.js代码:

    import Vue from 'vue'
    import Router from 'vue-router'
    import Home from './views/Home.vue'
    import Login from './views/Login.vue';
    import store from './store';
    Vue.use(Router)
    
    const router = new Router({
      mode: 'history',
      base: process.env.BASE_URL,
      routes: [
        {
          path: '/',
          name: 'home',
          component: Home
        },
        {
          path: '/login',
          name: 'login',
          component: Login
        },
        {
          path: '/about',
          name: 'about',
          meta: { auth: true },//about需要做登录鉴权
          component: () => import(/* webpackChunkName: "about" */ './views/About.vue')
        }
      ]
    })
    router.beforeEach((to, from, next) => {
      //to.meta.auth 表示需要做登录健全
      //不需要的 可以直接next
      if (to.meta.auth) {
        //store.state.token 表示已经登录 可以直接next
        //没有登录 跳转到/login 并携带参数redirect 方便登录后直接跳转到to.path
        if (store.state.token) {
          next();
        } else {
          next({
            path: '/login',
            query: { redirect: to.path }
          })
        }
      } else {
        next();
      }
    })
    export default router;

    axios拦截  

      axios.interceptors.request.use拦截axios所有http请求,如果存在token,则放入请求头。axios.interceptors.response.use拦截的axios的响应,如果token以及失效,则清除本地缓存和store存储并跳转到登录页面。

    http-interceptors.js代码:

    import axios from "axios";
    import store from "./store";
    import router from "./router";
    // 拦截axios所有http请求,预先放入token请求头
    axios.interceptors.request.use(config => {
      if (store.state.token) {
        // 若存在token,则放入请求头
        config.headers.token = store.state.token;
      }
      return config;
    });
    
    // 响应拦截器,提前预处理响应
    axios.interceptors.response.use(
      response => {
        // 如果code是-1,说明用户已注销或者token已过期
        // 此时需要重新登录,并且还要清除本地缓存信息和store数据
        if (response.status == 200) {
          const data = response.data;
          if (data.code == -1) {
            logoutFun()
          }
        }
        return response;
      },
      err => {
        if (err.response.status === 401) { // 未授权
          logoutFun()
        }
      }
    );
    
    function logoutFun() {
      // 清空本地缓存的token和store里的token
      store.commit("setToken", "");
      localStorage.removeItem("token");
      // 跳转至登录页,并携带用户退出时或token失效时的页面路由,方便登录后直接跳转到此页面。
      router.push({
        path: "/login",
        query: {
          redirect: router.currentRoute.path
        }
      });
    }
    服务端中间件
      服务端也需要做请求处理的中间件。如果请求不是req.path不是'/api/login'并且没有携带token,则返回错误状态码401。
    vue.config.js关键代码:
            app.use((req, res, next) => {
              //只对api开头的请求做拦截处理
              if (/^/api/.test(req.path)) {
                if (req.path == '/api/login' || req.headers.token) {
                  next();
                } else {
                  //设置错误状态码为401
                  res.sendStatus('401')
                  next();
                }
              } else {
                next();
              }
            })
  • 相关阅读:
    ERP类系统设计学习
    人工智能关键词
    系统性能
    连接不同服务器不同数据库
    socket一个例子
    SQLite
    asp.net 页面缓存、数据缓存
    原生js
    Android 网络调试 adb tcpip 开启方法
    C语言中string char int类型转换
  • 原文地址:https://www.cnblogs.com/superlizhao/p/10991300.html
Copyright © 2011-2022 走看看