用vue做登录鉴权功能

2,169 阅读6分钟
几乎每个vue项目里都会有登录鉴权功能,本文整理一个通用的登录鉴权功能模板。

注:文章为突出“登录鉴权”,只做关键代码展示,实际开发中,根据项目需求,修改代码。

通常一个vue项目中与登录鉴权功能有关的部分(文件)有:

Login 组件(Login.vue)

store(store.js)

router(router.js)

axios拦截(http-interceptors.js)

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赋初值的时候要取localStorage里的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 About from './views/About.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('./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里模拟后台接口'/api/login'

vue.config.js关键代码:

import axios from "axios";import store from "./store";import router from "./router";app.use((req, res, next) => {    //只对api开头的请求做拦截处理    if (/^\/api/.test(req.path)) {        if (req.path == '/api/login' || req.headers.token) {            next();        } else {            //设置错误状态码为xxx            res.sendStatus('401')            next();        }    } else {        next();    }})

感谢垂阅,

欢迎关注~

好看你就点点我