vuex + axios拦截器 + 导航守卫实现登录/注销功能

4,461 阅读3分钟

基本思想

首先要知道登录不仅仅是拿着用户名和密码通过接口发给后端就大功告成了(小白的我之前就是这样认为的)要从几个方面考虑

  • 异步登录,通过登录接口拿到token
  • 利用vuex的state管理token、用户信息等
  • 利用axios拦截器,拦截每一次请求/响应来处理token

token是用户登录成功的标识,每一次请求数据时都要发送token给后端验证 & 接收后端返回状态码判断当前用户登录状态

  • 利用导航守卫进行登录拦截
  • 密码传输加密(一般需要引入第三方加密,自行百度)

以下代码仅做参考

登录的基本实现

点击按钮触发事件submitForm login.vue文件中

methods: {
    submitForm(formName) {
        this.$refs[formName].validate(valid => {
            if(valid) {
                this.$store
                    .dispatch("userLogin", this.ruleForm)
                    .then(() => {
                        // 登录成功的提示
                        this.$router.push("home");
                    })
                    .catch(response => {
                        // 登录失败的提示
                    });
                }
            } else {
                // ...
            }
        })
    }
}

store.dispatch方法触发Action

actions: {
    userLogin({ commit }, userInfo) {
        return new Promise((resolve, reject) => {
            // 立即执行userLogin方法,详见下面的代码
            userLogin(userInfo.username, userInfo.password).then(response => {
                const data = response.data.data
                // 提交mutation来修改state
                commit('SET_TOKEN', data.token)
                // 调用setToken目的是把token存入到localStorage/sessionStorage/cookie中去
                // state中定义token通过getToken()获取token值
                setToken(data.token)
                resolve()
            }).catch(error => {
                reject(error)
            })
        })
    },
    // ... 
}

axios拦截器

我的拦截器目录是 /src/utils/request.js

// 创建axios实例
const service = axios.create({
    baseURL: '/api', // 根据项目自行配置
    timeout: 5000 // 请求超时时间
})

// request拦截器,在请求头中加入token
service.interceptors.request.use(config => {
    if (store.state.user.myToken) { // 从store的state中拿到token
        // config.headers.'后端接收token的名字'
        config.headers.myToken = store.state.user.myToken
    }
    return config
}, error => {
    Promise.reject(error)
})

// respone拦截器
service.interceptors.response.use(response => {
    const res = response.data
    if (res.errno === 501) {
        // MessageBox是elementUI的组件,提示用
        MessageBox.alert('系统未登录,请您登录', '错误', {
            confirmButtonText: '确定',
            type: 'error'
        }).then(() => { 
            // 登出
        })
        return Promise.reject('error')
    } else if (res.errno === 502) {
        // 写法类似
    } else {
        return response
    }
}, error => {
    // Message是elementUI的组件,提示用
    Message({
        message: '未知错误',
        type: 'error',
        duration: 5 * 1000
    })
    return Promise.reject(error)
})

export default service

上面说过的userLogin() 目录/src/api/login.js 与login.vue对应,统一存放请求代码,方便维护

// 引入上面的拦截器
import request from '@/utils/request'

export function userLogin(username, password) {
  const data = {
    username,
    password
  }
  return request({
    url: '/login',
    method: 'post',
    data
  })
}

导航守卫

在需要登录才能进入的路由中添加meta: { requireAuth: true }

export default new Router({
  mode: 'history',
  routes: [
    // ...
    {
      path: '/login',
      name: 'login',
      component: login,
      beforeEach: (to, from, next) => {
        if (to.meta.requireAuth) { // 判断是否需要登录权限
            // 判断是否有token
            if (store.state.user.myToken) {
                next() // 满足条件就放行
            } else {
                next('/login')
            }
        } else {
            next()
        }
      }
    },
  ]
})

总结

以上就是使用vuex + axios拦截器 + 导航守卫实现登录的大致流程。涉及到登出(注销)这里没有写,不过登录都会了注销并不难,走个接口清空本地保存的token就可以了。
以下是一些自问自答

  • 为什么要使用vuex

因为通过登录得到的用户信息在多个组件中都会用到,使用vuex直接通过state或getter访问变量很方便。但不要为了使用vuex而使用vuex

  • 既然用了vuex为什么还要将token存放到localStorage/sessionStorage/cookie中去

因为刷新会导致vuex的state中的变量重置为初始值(变量值会丢失

  • 那为什么要用vuex?

... 上面回答过了

[end]

本文使用 mdnice 排版