因我们把登录请求写在了vuex的actions中,当点击登录按钮,我们需要把用户名和密码dispatch给vuex的actions中的Login,这时将发送请求给后端登录接口进行验证,后端则去数据库中查看用户名和密码是否正确,若正确,则返回一个token值给前端,否则则登录失败

登录页面的代码实现如下:

// 这是点击登录按钮后的回调函数
// this.loginForm是存放用户名和密码的对象
this.$store.dispatch('Login', this.loginForm).then(() => {
   this.loading = false;
   // 当用户名和密码正确后,则将用户名和密码存放在cookie中,并设置过期时间
   setCookie("username",this.loginForm.username,15);
   setCookie("password",this.loginForm.password,15);
   // 跳转到首页
   this.$router.push({path: '/'})
}).catch(() => {
    this.loading = false
})

vuex中的Login实现代码如下:

state: {
    token: getToken()  // 首先是先获得浏览器中的token值
 },

 mutations: {
    SET_TOKEN: (state, token) => {
      state.token = token
    },
 },

 actions: {
    // 登录
    Login({ commit }, userInfo) {
      const username = userInfo.username.trim()
      return new Promise((resolve, reject) => {
        // login是发送登录请求的函数,其中将用户名和密码作为参数
        login(username, userInfo.password).then(response => {
          // 返回了成功的回调,则会获得token值
          const data = response.data
          const tokenStr = data.tokenHead+data.token
          // setToken函数会将tokenStr存在浏览器的cookie中
          setToken(tokenStr)
          // 并提交给mutations将tokenStr存在vuex中state中
          commit('SET_TOKEN', tokenStr)
          // 返回成功的回调
          resolve()
        }).catch(error => {
          reject(error)
        })
      }),
       // 登出
    LogOut({ commit, state }) {
      return new Promise((resolve, reject) => {
        logout(state.token).then(() => {
          commit('SET_TOKEN', '')
          commit('SET_ROLES', [])
          removeToken()
          resolve()
        }).catch(error => {
          reject(error)
        })
      })
    },

    // 前端 登出
    FedLogOut({ commit }) {
      return new Promise(resolve => {
        commit('SET_TOKEN', '')
        removeToken()
        resolve()
      })
    }
  },

存取token的函数文件

import Cookies from 'js-cookie'

const TokenKey = 'loginToken'
// 取出loginToken的值
export function getToken() {
  return Cookies.get(TokenKey)
}
// 设置loginToken的值在浏览器cookie中
export function setToken(token) {
  return Cookies.set(TokenKey, token)
}
// 移除loginToken
export function removeToken() {
  return Cookies.remove(TokenKey)
}

登录请求的函数

// 发送post请求并携带用户名和密码
export function login(username, password) {
  return request({
    url: '/admin/login',
    method: 'post',
    data: {
      username,
      password
    }
  })
}

在axios的每次请求的拦截器中都需要在请求头中加入token值,后端验证token值是否有效,若有效则返回数据

import axios from 'axios'
import { Message, MessageBox } from 'element-ui'
import store from '../store'
import { getToken } from '@/utils/auth'

// 创建axios实例
const service = axios.create({
  baseURL: process.env.BASE_API, // api的base_url
  timeout: 15000 // 请求超时时间
})

// request拦截器
service.interceptors.request.use(config => {
  if (store.getters.token) {
    config.headers['Authorization'] = getToken() 
    // 让每个请求携带自定义token 请根据实际情况自行修改
  }
  return config
}, error => {
  // Do something with request error
  console.log(error) // for debug
  Promise.reject(error)
})

// respone拦截器
service.interceptors.response.use(
  response => {
  /**
  * code为非200是抛错 可结合自己业务进行修改
  */
    const res = response.data
    if (res.code !== 200) {
      Message({
        message: res.message,
        type: 'error',
        duration: 3 * 1000
      })

      // 401:未登录;
      if (res.code === 401) {
        MessageBox.confirm('你已被登出,可以取消继续留在该页面,或者重新登录', '确定登出', {
          confirmButtonText: '重新登录',
          cancelButtonText: '取消',
          type: 'warning'
        }).then(() => {
          // 因token无效,所以则dispatch给FedLogOut移除cookie中和vuex中存放的token值
            // FedLogOut的实现在上面的vuex代码中
          store.dispatch('FedLogOut').then(() => {
            location.reload()// 为了重新实例化vue-router对象 避免bug
          })
        })
      }
      return Promise.reject('error')
    } else {
      // 响应没问题,则正常返回数据
      return response.data
    }
  },
  error => {
    console.log('err' + error)// for debug
    Message({
      message: error.message,
      type: 'error',
      duration: 3 * 1000
    })
    return Promise.reject(error)
  }
)

export default service

每次路由跳转前,在路由守卫中判断浏览器是否存在token值,若存在,则允许跳转,否则,则跳转到登录页面

const whiteList = ['/login'] // 不重定向白名单
router.beforeEach((to, from, next) => {
  if (getToken()) {
    // 存在token,且是要进入login页面,则让其跳转到首页
    if (to.path === '/login') {
      next({ path: '/' })
    } else {
       // 检查人物列表数据是否为空,则为空,则去请求人物数据,则放入vuex中getters
      if (store.getters.roles.length === 0) {
        store.dispatch('GetInfo').then(res => { // 拉取用户信息
          let menus=res.data.menus;
          let username=res.data.username;
          store.dispatch('GenerateRoutes', { menus,username }).then(() => {
             // 生成可访问的路由表
            router.addRoutes(store.getters.addRouters); // 动态添加可访问路由表
            next({ ...to, replace: true })
          })
        }).catch((err) => {
          store.dispatch('FedLogOut').then(() => {
            Message.error(err || 'Verification failed, please login again')
            next({ path: '/' })
          })
        })
      } else {
        // 不为空则正常跳转
        next()
      }
    }
  } else {
    // 如果不存在token,且是跳转到登录页,则正常跳转
    if (whiteList.indexOf(to.path) !== -1) {
      next()
    } else {
      next('/login')
      NProgress.done()
    }
  }
})

退出登录的代码实现如下:

// 点击了退出后的回调函数
logout() {
      // LogOut是vuex中的actions实现,其代码可以看上面的vuex代码
       // 清除了浏览器和vuex中的token值,并将存放人物列表置为空数组
      this.$store.dispatch('LogOut').then(() => {
        location.reload() // 为了重新实例化vue-router对象 避免bug
      })
}

以上若有不足之处欢迎指正!!!!!!!

Logo

基于 Vue 的企业级 UI 组件库和中后台系统解决方案,为数万开发者服务。

更多推荐