# Vue的登录验证流程

# 代码地址

Gitee码云 (opens new window)

# 前言

在我们的系统开发中,登录模块一直是很重要的一部分,现在大部分的系统都使用前后端分离的架构,前端的登录逻辑是比较重要的,它能拦截很大一部分的非法请求。本次实验参考了vue-router的官方例程,地址https://github.com/vuejs/vue-router/blob/dev/examples/auth-flow/

# 创建Vue项目

创建vue项目这里就不多说了,还得安装vue-router

vue add router

# 编写登录状态函数

编写auth功能函数,首先定义一个获取登录状态的方法,这里我的登录状态保存在local。然后定义一个更改登录状态的方法,这里写个空函数,待会可以在app.vue中重新定义这个函数。

export default {
    /**
     * 登录状态
     * @returns {boolean}
     */
    loggedIn(){
        return !!localStorage.token
    },
    /**
     * 更改登录状态
     */
    onChangeStatus(){}
}

这里我们的导航栏要根据登录状态变换登录还是登出状态,所以我们在我们的app.vue文件中获取登录状态,在data中创建了一个名为loggedIn的变量。然后在created周期中,对我们之前的更改状态函数进行定义。

<template>
  <div id="app">
    <h1>验证流程</h1>
    <router-view></router-view>
  </div>
</template>
<script>
import auth from './util/auth'

export default {
  data() {
    return {
      loggedIn:auth.loggedIn()
    }
  },
  created() {
    auth.onChangeStatus = (status)=>{
      this.loggedIn = status
    }
  }
}
</script>
<style>

</style>

# 编写路由守卫

router.js中编写requireAuth函数,编写这个函数的目的是在单独的路由中可以直接使用路由独享守卫,这里我只需要让Dashboard页面需要进行验证,下面是router.js的部分代码:

/**
 * 路由独享守卫
 * @param to
 * @param from
 * @param next
 */
function requireAuth(to,from,next){
  if(!auth.loggedIn()){
    next({
      path:'/login',
      query:{redirect:to.fullPath}
    });
  }else {
    next();
  }
}

const routes = [
  {
    path: '/',
    name: 'Home',
    component: Home
  },
  {
    path: '/about',
    name: 'About',
    component: () => import(/* webpackChunkName: "about" */ '../views/About.vue')
  },
  {
    path: '/dashboard',
    name: 'Dashboard',
    component: ()=>import('../views/Dashboard.vue'),
    beforeEnter:requireAuth
  },
  {
    path: '/login',
    name: 'Login',
    component: ()=>import('../views/Login')
  },
]

完成后可以发现,当我们访问Dashboard页面时,会自动跳转到登录页面,并且url上面还有登录重定向后的地址。

# 编写登录功能函数

现在路由的拦截功能已经成功了,我们得编写路由的登录逻辑。还是在刚刚的auth函数中,编写我们的登录函数。因为没有写后端,这里写个函数模拟一下后端,下面那个mockRequert函数就是。

 	/**
     * 登录函数
     * @param email
     * @param password
     * @returns {Promise<unknown>}
     */
    login(email, password) {
        return new Promise((resolve, reject) => {
            if (localStorage.token) {
                this.onChangeStatus(true)
            }
            mockRequest(email, password).then(res => {
                if (res.authenticated) {
                    localStorage.token = res.token;
                    this.onChangeStatus(true);
                    resolve({code: 200, msg: '登录成功', data: res.token})
                } else {
                    this.onChangeStatus(false);
                    resolve({code: 403, msg: '用户名密码不正确', data: ''})
                }
            }).catch(err => {
                console.log(err);
                reject(err);
            })
        })
    }


/**
 * 模拟后端
 * @param email 邮箱
 * @param password 密码
 * @returns {Promise<unknown>}
 */
function mockRequest(email, password) {
    return new Promise((resolve, reject) => {
        try {
            if (email === 'focuxin@qq.com' && password === '123') {
                resolve({
                    authenticated: true,
                    token: Math.random().toString(36).substring(7)
                })
            } else {
                resolve({
                    authenticated: false
                })
            }
        } catch (e) {
            reject(e)
        }
    })
}

# 编写登录页面

<template>
  <div id="login">
    <h1>登录页面</h1>
    <form>
      邮箱:
      <input type="text" name="email" v-model="email">
      密码:
      <input type="text" name="password" v-model="password">
    </form>
    <button @click="doLogin">登录</button>
    <p v-if="error">用户名密码不正确</p>
  </div>
</template>

<script>
import auth from '../util/auth'

export default {
  name: "Login",
  data() {
    return {
      email:'focuxin@qq.com',
      password:'',
      error:false
    }
  },
  methods: {
    doLogin(){
      auth.login(this.email,this.password).then(res=>{
        if(res.code !== 200){
          this.error = true;
          console.log(res)
        }else {
          console.log(res)
          this.$router.replace(this.$route.query.redirect || '/');
        }
      }).catch(err=>{
        console.error(err)
        this.error = true
      })
    }
  }
}
</script>

<style scoped>

</style>

登录成功,跳转访问页面:

登录失败,显示错误信息:

# 编写登出函数

登出函数很简单,只需要先删除local里面的token,然后再把登录状态修改成未登录就好了,在auth函数里面添加logout函数

    /**
     * 登出函数
     */
    logout() {
        delete localStorage.token;
        this.onChangeStatus(false);
    }

然后在路由里面新建一个/logout的路由,参数如下:

{
    path: '/logout',
    beforeEnter(to,from,next){
      auth.logout()
      next('/login');
    }
  }

然后可以在app.vue上加俩个导航

<router-link to="/login" v-if="!loggedIn">登录</router-link>
<router-link to="/logout" v-if="loggedIn">登出</router-link>
Last Updated: 10/18/2020, 7:00:42 PM