开课吧Vue电商项目实战(一)——登录认证

安装cube-ui

vue add cube-ui

配置router

需要验证时添加meta标签,确认哪个路由需要受保护

import Vue from 'vue'
import Router from 'vue-router'
import Home from './views/Home.vue'
import Login from './views/Login.vue'
import {store} from 'vuex'

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
      },
      // route level code-splitting
      // this generates a separate chunk (about.[hash].js) for this route
      // which is lazy-loaded when the route is visited.
      component: () => import( /* webpackChunkName: "about" */ './views/About.vue')
    }
  ]
})

router.beforeEach((to, from, next) => {
  if (to.meta.auth) {
    // 需要认证,则检查令牌
    if (store.state.token) {
      next()
    } else {
      // 去登陆
      next({
        path: '/login',
        query: {
          redirect: to.path
        }
      })
    }
  } else {
    next()
  }
})

export default router

在store中设置全局token

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

export default new Vuex.Store({
  state: {
    token: ''
  },
  mutations: {
    setToken(state, token) {
      state.token = token
    }
  },
  actions: {

  }
})

Login.vue组件写入

<template>
  <cube-form :model="model" :schema="schema" @validate="handlerValidate" @submit="handlerLogin"></cube-form>
</template>

<script>
import { type } from 'os';
import { log } from 'util';
export default {
  data () {
    return {
      model: {
        username: '',
        password: ''
      },
      schema: {
        fields: [
          {
            type: 'input',
            modelKey: 'username',
            label: '用户名',
            props: {
              placeholder: '请输入用户名'
            },
            rules: {
              required: true
            },
            messages: {
              required: '用户名为必填项'
            },
            trigger: 'blur'
          },
          {
            type: 'input',
            modelKey: 'password',
            label: '密码',
            props: {
              placeholder: '请输入密码',
              type: 'password',
              eye: {
                open: false
              }
            },
            rules: {
              required: true
            },
            messages: {
              required: '密码为必填项'
            },
            trigger: 'blur'
          },
          {
            type: 'submit',
            label: '登录'
          }
        ]
      }
    }
  },
  methods: {
    handlerLogin (e) {
      e.preventDefault()
      console.log('登录')
    },
    handlerValidate (ret) {
      console.log('校验' + ret)
    },

  },
}
</script>

<style lang="scss" scoped>
</style>

main.js中全局注册axios

import Vue from 'vue'
import './cube-ui'
import App from './App.vue'
import router from './router'
import store from './store'
import axios from 'axios'

Vue.config.productionTip = false

Vue.prototype.axios = axios

Login组件中写入,异步请求服务器比对用户名和密码,成功后跳转到原先未登录前的页面

<template>
  <cube-form :model="model" :schema="schema" @validate="handleValidate" @submit="handleLogin"></cube-form>
</template>

<script>
export default {
  data () {
    return {
      model: {
        username: '',
        password: ''
      },
      schema: {
        fields: [
          {
            type: 'input',
            modelKey: 'username',
            label: '用户名',
            props: {
              placeholder: '请输入用户名'
            },
            rules: {
              required: true
            },
            messages: {
              required: '用户名为必填项'
            },
            trigger: 'blur'
          },
          {
            type: 'input',
            modelKey: 'password',
            label: '密码',
            props: {
              placeholder: '请输入密码',
              type: 'password',
              eye: {
                open: false
              }
            },
            rules: {
              required: true
            },
            messages: {
              required: '密码为必填项'
            },
            trigger: 'blur'
          },
          {
            type: 'submit',
            label: '登录'
          }
        ]
      }
    }
  },
  methods: {
    async handleLogin (e) {
      e.preventDefault()
      const res = await this.axios.get('/api/login', {
        params: {
          username: this.model.username,
          password: this.model.password
        }
      })
      console.log(res)
      const { code, token, message } = res.data
      console.log(code, token, message)
      if (code === 0) {
        // 登录成功
        localStorage.setItem('token', token) // 缓存至本地
        this.$store.commit('setToken', token)
        let redirect = '/'
        if (this.$route.query.redirect) {
          redirect = this.$route.query.redirect
        }
        this.$router.push(redirect)
      } else {
        const toast = this.$createToast({
          time: 2000,
          txt: message || '登录失败',
          type: 'error'
        })
        toast.show()
      }
    },
    handleValidate (ret) {
      console.log('校验' + ret)
    }
  }
}
</script>

既然要请求服务器了,我们可以在vue.config.js的configureWebpack中的devServer中写一个开发用的自定义服务器

module.exports = {
  css: {
    loaderOptions: {
      stylus: {
        'resolve url': true,
        'import': [
          './src/theme'
        ]
      }
    }
  },
  pluginOptions: {
    'cube-ui': {
      postCompile: true,
      theme: true
    }
  },
  configureWebpack: {
    devServer: {
      before(app) {
        app.get('/api/login', function (req, res) {
          const {username, password} = req.query
          if (username === 'Vansal' && password === '123') {
            res.json({
              code: 0,
              token: 'haha'
            })
          } else {
            res.json({
              code: -1,
              message: '用户名或密码错误'
            })
          }
        })
      }
    }
  }
}

当我们每次请求服务器是都要携带token,我们可以设置所有的http请求预先放入token令牌

根目录下新建http-interceptor.js文件,写入

import axios from 'axios'
import store from './store'

axios.interceptors.request.use(
  config => {
    if (store.state.token) {
      config.headers.token = store.state.token
      return config
    }
  }
)

这个文件只要执行一次就可以了,所以只要把它放入main.js中就可以了,因为导入后会自动执行一遍

import interceptor from './http-interceptor'

设置登出,app.vue中写入

<template>
  <div id="app">
    <div id="nav">
      <router-link to="/">Home</router-link>|
      <router-link to="/about">About</router-link>|
      <router-link to="/login" v-if="!isLogin">login</router-link>|
      <a @click="logout" v-if="isLogin">logout</a>
    </div>
    <router-view />
  </div>
</template>
<script>
import { mapGetters } from 'vuex'
export default {
  computed: {
    ...mapGetters(['isLogin'])
  },
  methods: {
    logout () {
      this.axios.get('/api/logout')
    }
  }
}
</script>

this.axios.get('/api/logout') 登出时发送了请求

所以在vue.config.js中加入

app.get('/api/logout', function (req, res) {
          res.json({
            code: -1
          })
        })

在响应回来之前,我们要判断用户是否已注销或token令牌是否已过期,所以在http-interceptor.js中配置响应拦截器

// 响应拦截器
axios.interceptors.response.use(
  response => {
    // 如果code是-1,说明用户已注销或token已过期
    // 此时需要重新登录,并且清除本地的缓存信息
    if (response.status === 200) {
      const data = response.data
      if (data.code === -1) {
        store.commit('setToken', '')
        localStorage.removeItem('token')
        // 跳转至登录页面
        router.push({
          path: '/login',
          query: {
            redirect: router.currentRoute.path
          }
        })
      }
    }
    return response
  }
)
发布了121 篇原创文章 · 获赞 13 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/Vansal/article/details/94841647